简体   繁体   English

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

[英]How to instantiate a child class using its parent factory in __construct

I have a Class A which must be instantiated using other multiples objects 我有一个A类,必须使用其他多个对象进行实例化

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

To save me the trouble of this class instantiation, I have set up a factory for this class. 为了省去这个类实例化的麻烦,我为这个类设置了一个工厂。

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

I have a class B with extends class A. My problem is that I can't figure out how to instantiate the A class within the B class in order to access the property 'foo'. 我有一个扩展类A的B类。我的问题是我无法弄清楚如何在B类中实例化A类以访问属性'foo'。

It felt natural to me to try: 我很自然地尝试:

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

but it generates a notice error when trying to access the object A properties: 但在尝试访问对象A属性时会产生通知错误:

Undefined property: A::$foo

How can I use the class A factory to instantiate A easily within its child classes? 如何使用A类工厂在其子类中轻松实例化A? Thank you. 谢谢。

You try to use A_Factory::create_A() in the same way as you would use parent::__construct() . 您尝试以与使用parent::__construct()相同的方式使用A_Factory::create_A() parent::__construct() However, these are two completely different calls. 但是,这是两个完全不同的调用。

parent::__construct() 父:: __构建体()

parent resolves to A . parent解析为A The current object $this is an instance of A (because every instance of B is also an instance of A due to inheritance). 当前对象$thisA的实例(因为B每个实例由于继承而也是A的实例)。 In this case, the call is not a static call , although the operator :: has been used ( $this stays the same). 在这种情况下,虽然运算符::已被使用( $this保持不变),但调用不是静态调用

The following code works: 以下代码有效:

(given that foo is not private ) (假设foo不是private

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

This one works too: 这个也有效:

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

Factory

A_Factory::createA() is a static call , because A_Factory is not in the inheritance tree of B . A_Factory::createA()是一个静态调用 ,因为A_Factory不在B的继承树中。 Also A_Factory creates and returns a new instance of A . A_Factory 创建返回 A的新实例。 So as soon as this has been called, you have two different objects: $this is still the unchanged B instance and you created a different instance of A without assigning it to any variable. 因此,只要调用它,就会有两个不同的对象: $this仍然是未更改的B实例,并且您创建了一个不同的A实例,而不将其分配给任何变量。

A possible approach is to move the factory method into A itself. 一种可能的方法是将工厂方法移动到A本身。

This will work: 这将有效:

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();

This makes use of late static binding with the static keyword. 这使用了与static关键字的后期静态绑定 static resolves to the class name of the called class, so that it is A in A::create() and B in B::create() . static解析为称为类的类名,所以它是AA::create()BB::create()

Note the difference to self , which always resolves to the class where the method is declared (in this case it would be always A ) 注意与self的区别,它总是解析为声明方法的类(在这种情况下它总是A

You have a slight misunderstanding of how inheritance works. 您对继承如何工作有轻微的误解。 I think that because of that line in B's constructor: 我认为因为B的构造函数中的那一行:

A_Factory::create_A();

The parent is not a property of the child class. 父级不是子级的属性。 If you create a new A([...]) within B's constructor, it will be an other class, completely separated from your B, and there is no way to "merge" it to an existing object. 如果在B的构造函数中创建一个new A([...]) ,它将是另一个类,与B完全分离,并且无法将其“合并”到现有对象。 To construct the parent from a child class, you would do that: 要从子类构造父类,您可以这样做:

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

Here is a way of creating your classes, using a factory and some type-hinting. 这是一种使用工厂和一些类型提示创建类的方法。 Notice how I moved the different new XYZ() so that they are not in your classes constructors. 注意我是如何移动不同的new XYZ()以便它们不在类构造函数中。 Naked news in constructors is somewhat considered bad practice as it hides the dependencies of your classes. 构造函数中的裸体消息在某种程度上被认为是不好的做法,因为它隐藏了类的依赖关系。

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);

The real answer : you want your factory to be a dependency injection container, such as Auryn , and by using type-hints your classes would be recursively created with their dependencies, using reflection . 真正的答案是 :您希望您的工厂成为依赖注入容器,例如Auryn ,并且通过使用类型提示,您的类将使用反射以其依赖关系递归创建。

in your case (adapted from an exemple in auryn's github repo): 在你的情况下(改编自auryn的github回购中的例子):

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);

Using reflection, Auryn can recursively understand what are the components your classes need, instantiate them and pass them to your classes constructors. 使用反射,Auryn可以递归地理解您的类所需的组件,实例化它们并将它们传递给类构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM