从静态方法中创建类实例

Posted

技术标签:

【中文标题】从静态方法中创建类实例【英文标题】:Create class instance from within static method 【发布时间】:2011-06-07 05:02:27 【问题描述】:

正如标题所说,我想从同一个类的静态方法中创建一个类的实例。到目前为止,我发现我可以通过这样做:

class Foo

 public $val;

 public static function bar($val)
  $inst = new Foo;
  $inst->val = $val;
  return $inst;
 


因此让我这样做。

$obj = Foo::bar("some variable");

这太棒了。

现在是问题。有没有我不知道的更简单的方法,或者有什么捷径可以达到相同的结果?以这种方式创建实例有什么优点或缺点吗?

谢谢。

【问题讨论】:

您这样做的原因是什么?为什么不使用普通的$obj = new Foo("some variable"); 对我来说,用在某个时候已经创建的构造函数创建一些东西是没有意义的。例如,在当前项目中,我使用 Profile::get() 加载(在某些时候)已经“构建”的配置文件。也许我在滥用构造函数或使用它作为重载的答案。 【参考方案1】:

超级迟到,但发现这很有用。

一个很好的例子是奥迪 UI 库中的这个静态方法,它从 TextFieldstatic 方法 upgradeElements 中返回实例化 TextField 类的 Array

/**
 * Class constructor for Textfield AUI component.
 * Implements AUI component design pattern defined at:
 * https://github.com/...
 *
 * @param htmlElement element The element that will be upgraded.
 */
export default class Textfield extends Component 

  /**
   * Upgrades all Textfield AUI components.
   * @returns Array Returns an array of all newly upgraded components.
   */
  static upgradeElements() 
    let components = [];
    Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => 
      if (!Component.isElementUpgraded(element)) 
        components.push(new Textfield(element));
      
    );
    return components;
  ;

  constructor(element) 
    super(element);
  
... 

在 repo 中查看其余部分 https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25

【讨论】:

【参考方案2】:

他们这样做很好。还有一些其他事情可以让您的生活更轻松,您也可以这样做。

    不要对类名进行硬编码。如果您使用的是 5.3+,请使用关键字 static。这样,如果您扩展类,新函数也可以实例化该类:

    public static function bar($var) 
        $obj = new static();
        $obj->var = $var;
        return $obj;
    
    

    然后你可以在任何扩展类中使用它而无需覆盖任何东西。

    确定$var 是否应该通过构造函数而不是在构造后设置。如果对象依赖于它,你应该需要它。

    public function __construct($var) 
        $this->var = $var;
    
    

    这样你就不能在不设置变量的情况下实例化对象。

    通过静态方法强制实例化类。如果你在那里做任何你需要做的事情,那么将构造函数设置为受保护的或私有的。这样,就无法绕过静态方法。

    protected function __construct() 
    private function __construct() 
    

希望对你有帮助……

编辑:根据您上面的评论,我觉得您正在尝试实现Singleton Design Pattern。关于为什么它不是一个好主意以及它可能做的坏事,有大量的信息。它也有用途。

但根据您的具体操作,还有一些其他模式可能对您有用。

如果您尝试使用相同的步骤创建不同的对象,可以使用Factory Method。 如果所有对象都以相同的开头然后进行自定义,您可以使用Prototype Pattern。 如果创建对象的成本特别高,您可以使用Object Pool。

但要考虑的一件事是,在 php 中对象的重量非常轻。不要试图避免仅仅为了这个开销而创建一个新对象。避免多次执行繁重的操作,例如数据库查询或文件系统访问。不过不用担心调用new Foo(),除非foo的构造函数特别重……

【讨论】:

【参考方案3】:

这看起来像一个简单的工厂方法模式。

你有一个很好的优势:假设将来你想开始使用不同的实现(但做同样的事情)。使用工厂,您只需更改创建者方法即可更改在复杂系统的许多地方创建的所有对象。请注意,如果您使用外部类(如下第一个链接中所示),这会更容易。

保持它现在的样子,你也可以继承这个类并重写这个方法来创建一个更复杂的对象。我不认为这是您想要在这里实现的目标。

无论如何,这对于启用测试驱动开发、抽象和许多其他好东西是件好事。

链接:

    Php patterns Factory method pattern on wikipedia

【讨论】:

【参考方案4】:

如果你只是创建一个对象,这不是很有用。你可以只调用一个构造函数。但是如果你正在做一些更复杂的事情(比如你从某种单例模式开始,但没有在这个例子中包含所有细节),那么:

这听起来很对。如果你想阻止像这样以默认方式创建的对象:

$obj = new Foo("Some Variable");

你可以添加一个私有构造函数:

class Foo

 public $val;

 private __construct()

 public static function bar($val)
  $inst = new Foo;
  $inst->val = $val;
  return $inst;
 

现在你强制人们使用你的静态类。可能不再需要在函数中设置 val,因此您甚至可以将值参数添加到您的私有构造函数中,但在您的'bar'函数

【讨论】:

以上是关于从静态方法中创建类实例的主要内容,如果未能解决你的问题,请参考以下文章

在函数中创建类并访问在包含函数范围内定义的函数

在JAVA中啥是顶级类啊

如何在 Java 静态块中创建本地类? [复制]

java 中类的加载顺序

在另一个类中创建类实例的问题

修复此“从实例方法写入静态字段”findbugs 警告的最佳方法是啥?