从静态方法中创建类实例

问题描述 投票:42回答:4

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

class Foo{

 public $val;

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

}

因此我可以这样做

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

这很好。

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

谢谢。

php oop class instance
4个回答
89
投票

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

  1. 不要硬编码类名。 如果你是在5.3以上版本,使用关键字 static. 这样,如果你扩展了这个类,新的函数也可以实例化那个类。

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

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

  2. 弄清楚是否 $var 应该通过构造函数传递进来,而不是在构造后设置。 如果对象依赖于它,你应该要求它。

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

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

  3. 通过静态方法来强制实例化类。 如果你在里面做了任何你需要做的事情,那就把构造函数做成保护的或者私有的。 这样一来,别人就不能绕过静态方法了。

    protected function __construct() {}
    private function __construct() {}
    

希望能帮到你...

编辑一下。 根据你上面的评论 在我看来 你是想实现一个静态方法 单人设计模式. 有大量的信息,关于为什么它不是一个好主意,以及它可能做的坏事。 它也有用途。

但是有一些其他的模式可能对你有用,这取决于你到底在做什么。

  • 你可以使用 工厂方法 如果你想用同样的步骤创建不同的对象。
  • 如果所有的对象一开始都是一样的,然后是自定义的,你可以使用 原型模式.
  • 你可以用一个 对象池 如果创建你的对象特别贵的话。

但有一点需要考虑,就是在PHP中对象的重量很轻。 不要为了这个开销而试图避免创建一个新的对象。 避免做重的事情,比如数据库查询或者多次访问文件系统。 但是不用担心调用 new Foo() 除非 foo'的构造函数特别重... ...


3
投票

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

你有一个很好的优势:假设将来你想开始使用一个不同的实现(但做的是同样的事情)。使用工厂,你可以简单地通过改变创建者方法来改变一个复杂系统的许多地方创建的所有对象。请注意,如果你使用一个外部类,这将更容易工作(就像下面第一个链接中的那样)。

保持现在的样子,你也可以对这个类进行子类化,然后重写方法来创建一个更复杂的对象。我想这不是你想在这里实现的。

总之,这很好的实现了测试驱动开发、抽象和其他很多好的东西。

链接。

  1. Php模式
  2. 维基百科上的工厂方法模式

0
投票

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

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

$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的需求可能会消失,所以你甚至可以将value参数添加到你的私有构造函数中,但在你的 "bar "函数中做其他事情(你大概想做的,比如检查某种单子模式)。


0
投票

超级晚,但发现这个很有用。

一个很好的例子是奥迪UI库中的这个静态方法,返回一个 Array 实例化的 TextField 内行 TextField's static 办法 upgradeElements.

/**
 * 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);
  }
... 

其余内容请参见回帖https:/github.comaudiaudi-uiblobmastersrctextfieldtextfield.js#L25。

© www.soinside.com 2019 - 2024. All rights reserved.