PHP静态工厂方法:动态实例化调用类的实例

10
这个PHP问题与这个问题有关,但有点不同。我有一个名为create()的静态工厂方法,它实例化一个类实例。我希望该方法在运行时动态地实例化调用它的(子)类的实例。因此,在运行时必须确定要实例化的类。但是我希望在子类中不重新定义静态工厂方法来实现这一点(在我的示例中这是完全有效的,因为子类没有新的数据成员需要初始化)。这是否有可能?
class Foo {

  private $name;

  public static function create($name) {

    //HERE INSTED OF:
    return new Foo($name);
    //I WANT SOMETHING LIKE:
    //return new get_class($this)($name);//doesn't work
    //return self($this);//doesn't work either

  }

  private function __construct($name) {

    $this->name = $name;

  }

  public function getName() {

    return $this->name;

  }

}

// the following class has no private data, just extra methods:

class SubFoo extends Foo {

  public function getHelloName() {

    echo "Hello, ", $this->getName(), ".\n";

  }

}


$foo = Foo::create("Joe");
echo $foo->getName(), "\n"; // MUST OUTPUT: Joe

$subFoo = SubFoo::create("Joe");
echo $subFoo->getHelloName(), "\n"; // MUST OUTPUT: Hello, Joe.
3个回答

11

你必须使用延迟静态绑定来创建对象 - 方法get_called_class()非常有用。第二个选项是使用static关键字。

例如:

class Foo 
{
    private $name;

    public static function create($name) 
    {
        $object = get_called_class();
        return new $object($name);
    }

    private function __construct($name) 
    {
        $this->name = $name;
    }

    public function getName() 
    {
        return $this->name;
    }
}

class SubFoo extends Foo 
{
    public function getHelloName() 
    {
        return "Hello, ". $this->getName();
    }
}

$foo = Foo::create("Joe");
echo $foo->getName(), "\n";

$subFoo = SubFoo::create("Joe");
echo $subFoo->getHelloName(), "\n";

并输出:

Joe
Hello, Joe

1
因为你必须创建对象SubFoo,所以要了解关于后期状态绑定的知识... 还有一个问题点。static也不错。 - Piotr Olaszewski
1
抱歉,我的意思是 static 而不是 self - Kamil Karkus
什么是“downvote”?我没有点踩。如果我不小心点了踩,然后在十分之一秒后又点了赞,也许这会显示在某个地方,但我不确定通知是否会被SE代码删除。无论如何,如果有人点了踩,那不是我。谢谢。 - John Sonderson
无论如何,使用get_called_class()相比于static有什么优势呢?谢谢。 - John Sonderson
get_called_class() 可以用于检索调用类的名称字符串,但 static 创建对象。 - Piotr Olaszewski

7

return new static();

这里已经使用了保留关键字static


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - John Sonderson
1
哦,抱歉我的错,应该是static关键字。 - Kamil Karkus
好的,return new static($name) 对我来说可以工作。请更新您的答案,以便我可以接受它。谢谢。 - John Sonderson

-3

是的,使用php的后期静态绑定功能是有可能实现的。

与其

$foo = Foo::create("Joe");
echo $foo->getName(), "\n"; // MUST OUTPUT: Joe

$subFoo = SubFoo::create("Joe");
echo $foo->getHelloName(), "\n"; // MUST OUTPUT: Hello, Joe.

尝试一下这个。
echo parent::getName();
echo self::getHelloName();

如果我有一系列的子类,那么parent就无法使用了。我认为使用static($parameterList)是我寻找的最佳答案。 - John Sonderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接