从父类实例化子类(PHP)

8

我有一个包含工厂模式函数的类:

abstract class ParentObj {
    public function __construct(){ ... }
    public static function factory(){
        //returns new instance
    }
}

我需要让子类能够调用工厂函数并返回调用类的实例:$child = Child::factory(); 最好不要在子类中重写工厂函数。
我尝试了多种不同的方法都没有成功。我希望避免使用反射的解决方案,例如__CLASS__
(如果有关系的话,我正在使用PHP 5.2.5)
2个回答

12

如果您可以升级到 PHP 5.3 (2009年6月30日发布),请查看后期静态绑定,这可能会提供一个解决方案:

abstract class ParentObj {
    public function __construct(){}
    public static function factory(){

        //use php5.3 late static binding features:
        $class=get_called_class();
        return new $class;
    }
}


class ChildObj extends ParentObj{

    function foo(){
       echo "Hello world\n";
    }

}


$child=ChildObj::factory();
$child->foo();

我现在正在尝试使用RC4,如果没有其他人在此期间介入,我很快就会尝试一些代码... - Paul Dixon
LSB似乎是我自己能找到的最好的解决方案。 在我升级之前,我能想到的最好的方法就是将子名称传递给factory(),或者将名称定义为属性并从factory()中获取。 - Austin Hyde
1
在 PHP 5.3 中,我认为您只需要使用这个单语句:return new static();而不是这两个语句 $class=get_called_class(); return new $class; - Buttle Butkus
除了可读性之外,使用get_called_class()而不是$this的原因是什么? - tylersDisplayName
1
@ButtleButkus 我可以确认 return new static(); 和非常相似的 return new static; 在 PHP 5.6.38 中都是有效的。顺便说一句,return new get_called_class(); 也是有效的。 - Tylla
显示剩余4条评论

0
在我看来,您正在尝试做的事情毫无意义。

工厂模式的工作方式如下:

abstract class Human {}

class Child extends Human {}
class Fool  extends Human {}

class HumanFactory
{
    public static function get($token)
    {
        switch ($token)
        {
            case 'Kid' : return new Child();
            case 'King': return new Fool();
            default    : throw new Exception('Not supported');
        }
    }
}

$child = HumanFactory::get('Kid');

那就是一个完整的工厂模式。我只是指一个静态方法来绕过new操作符,并为子类提供可读性和链接。 - Austin Hyde
为什么你想要绕过new操作符? - Philippe Gerber
2
使用你的例子,new Child()->foo() 不起作用。通过添加“工厂”方法(如我所使用的),您可以执行 Child::factory()->foo()->bar(),这比在几行上分开更易读(在我看来)。我想这是一个观点问题,公平地说,你实现的工厂很有用,只不过不适用于我正在寻找的东西。 - Austin Hyde
1
你可以使用HumanFactory::get('Kid')->foo()->bar()。其中foo()和bar()是Human类和/或Child类中的方法。;-) - Philippe Gerber
你的模式并不总是适用的,如果你的Human类实现了一个静态的get函数来实现单例机制,那么你就不需要在每个子类中编写get函数(除非你疯了或者很无聊),你只需要返回你所请求的单例,例如在你的示例中是Child或Fool。 - vdegenne

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