I have a Class A which must be instantiated using other multiples objects
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'.
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:
Undefined property: A::$foo
How can I use the class A factory to instantiate A easily within its child classes? Thank you.
Following the object oriented methodology, a child class can be instantiated as an object that can inherit the attributes of the parent class.
Example# __construct() is the most common magic method in PHP, because it is used to set up a class when it is initialized. The opposite of the __construct() method is the __destruct() method. This method is called when there are no more references to an object that you created or when you force its deletion.
We can do this by using the special function call parent::__construct(). The "parent" part means "get the parent of this object, and use it", and the __construct() part means "call the construct function", of course. So the whole line means "get the parent of this object then call its constructor".
You try to use A_Factory::create_A()
in the same way as you would use parent::__construct()
. However, these are two completely different calls.
parent
resolves to A
. The current object $this
is an instance of A
(because every instance of B
is also an instance of A
due to inheritance). In this case, the call is not a static call, although the operator ::
has been used ($this
stays the same).
(given that foo
is not 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()
is a static call, because A_Factory
is not in the inheritance tree of B
. Also A_Factory
creates and returns a new instance of 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.
A possible approach is to move the factory method into A
itself.
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
resolves to the class name of the called class, so that it is A
in A::create()
and B
in B::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
)
You have a slight misunderstanding of how inheritance works. I think that because of that line in B's constructor:
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. 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. 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.
in your case (adapted from an exemple in auryn's 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);
Using reflection, Auryn can recursively understand what are the components your classes need, instantiate them and pass them to your classes constructors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With