如何使用__construct中的父工具实例化子类

时间:2015-09-12 18:36:07

标签: php oop factory

我有一个必须使用其他多个对象实例化的A类

class A{
   function __construct(new X(), new Y(), new Z()){
      $this->foo = 'foo';
   }
}

为了省去这个类实例化的麻烦,我为这个类设置了一个工厂。

class A_Factory{
    public static function create_A(){
        return new A(new X(), new Y(), new Z());
    }
}

我有一个扩展类A的B类。我的问题是我无法弄清楚如何在B类中实例化A类以访问属性“foo”。

我觉得尝试很自然:

class B extends A{
   function __construct(){
      A_Factory::create_A();  
   }
}

但在尝试访问对象A属性时会产生通知错误:

Undefined property: A::$foo

如何使用A类工厂在其子类中轻松实例化A?谢谢。

2 个答案:

答案 0 :(得分:4)

您尝试使用A_Factory::create_A()的方式与使用parent::__construct()的方式相同。但是,这是两个完全不同的电话。

父:: __构建体()

parent解析为A。当前对象$thisA的实例(因为B的每个实例由于继承而也是A的实例)。在这种情况下,虽然已使用运算符::$this保持不变),但呼叫不是静态调用

以下代码有效:

(鉴于foo不是private

class B extends A
{
    function __construct()
    {
        parent::__construct(new X, new Y, new Z);
        echo $this->foo;
    }
}

这个也适用:

class B extends A
{
    function __construct()
    {
        A::__construct(new X, new Y, new Z);
        echo $this->foo;
    }
}

A_Factory::createA()静态调用,因为A_Factory不在B的继承树中。此外,A_Factory 创建返回 A的新实例。因此,只要调用此对象,就会有两个不同的对象:$this仍然是未更改的B实例,并且您创建了一个不同的A实例,而不将其分配给任何变量。< / p>

一种可行的方法是将工厂方法移动到A本身。

这将有效:

class A
{
    function __construct(X $x, Y $y, Z $z)
    {
        $this->foo = 'foo';
    }
    public static function create()
    {
        return new static (new X, new Y, new Z);
    }
}

class B extends A
{
}

// Instantiating:
$a = A::create();
$b = B::create();

这会将late static bindingstatic关键字结合使用。 static解析为被调用类的类名,因此A中的A::create()B中的B::create()

请注意self的差异,它总是解析为声明的方法的类(在这种情况下,它总是A

答案 1 :(得分:3)

您对继承的工作原理略有误解。我认为因为B的构造函数中的那一行:

A_Factory::create_A();

父级不是子级的属性。如果在B的构造函数中创建new A([...]),它将是另一个类,与B完全分离,并且无法将其“合并”到现有对象。要从子类构造父类,您可以这样做:

class B {
    function __construct() {
        parent:__construct(new X(),new Y(),new Z());
    }
}

这是一种使用工厂和一些类型提示创建类的方法。请注意我是如何移动不同的new XYZ(),以便它们不在您的类构造函数中。构造函数中的裸体消息在某种程度上被认为是不好的做法,因为它隐藏了类的依赖关系。

class B_Factory {
    public static function create_B(X $X,Y $Y, Z $Z) {
        return new B($X, $Y, $Z);
    }
}

class X {}
class Y {}
class Z {}

class A {
    public function __construct(X $X, Y $Y, Z $Z) {
        $this->foo = "foo";
    }
}

class B extends A {
    public function __construct(X $X, Y $Y, Z $Z) {
        parent::__construct($X,$Y,$Z);
    }
}

$B = B_Factory::create_B(new X(), new Y(), new Z());
var_dump($B->foo);

真正的答案:您希望您的工厂成为依赖注入容器,例如Auryn,并且通过使用类型提示,您的类将使用其依赖项递归创建,使用reflection

在你的情况下(改编自auryn的github repo中的例子):

class X {}
class Y {}
class Z {}

class A {
    public function __construct(X $X, Y $Y, Z $Z) {
        $this->foo = "foo";
    }
}

class B extends A {
    public function __construct(X $X, Y $Y, Z $Z) {
        parent::__construct($X, $Y, $Z);
    }
}

$injector = new Auryn\Injector;
$B = $injector->make('B');
var_dump($B->foo);

使用反射,Auryn可以递归地理解你的类需要什么组件,实例化它们并将它们传递给类构造函数。