1

In PHP (Symfony 3);

I want to reference an existing object A in another object B which class extends the one of object A, like this:

    class A {
       private $property1;
       private $property2;
       public function __construct($p1,$p2){
          $this->property1 = $p1;
          $this->property2 = $p2;
       }

    }

    class B extends A {
       private $property3;
       public function __construct($objectA,$p3){
         $this = $objectA;
         $this->property3 = $p3;
       }
    }
    $a = new A('p1','p2');
    $b = new B($a,'p3');

This does not work and throw the following error at the statement $this = $objectA:

Compile Error: Cannot re-assign $this

Which are documented and explain there and there. I am looking for a workaround.

Community
  • 1
  • 1
nyluje
  • 3,573
  • 7
  • 37
  • 67
  • `$this = $object` i mean you need to study the basic of programming keywords and tokens , variables etc. – M A SIDDIQUI Jan 31 '17 at 13:06
  • `$this` is read-only, it can't be reassigned directly. If you would like to use the properties of `$a` in `$b`, you could make the fields in class A protected and update the fields in class B to the ones in $a – Antony Jan 31 '17 at 13:09
  • I think a bit of study of class/object inheritance might be necessary, so that you understand what inheritance actually means – Mark Baker Jan 31 '17 at 13:09
  • see my update answer – Constantin Galbenu Jan 31 '17 at 13:25

3 Answers3

1

You must call parent constructor and also make property1 and property2 visible in class B

<?php
 class A {
       private $property1;
       private $property2;
       public function __construct($p1,$p2){
          $this->property1 = $p1;
          $this->property2 = $p2;
       }

       public function getProperty1()
       {
           return $this->property1;
       }

       public function getProperty2()
       {
           return $this->property2;
       }

    }

    class B extends A {
       private $property3;
       public function __construct($objectA,$p3){
         parent::__construct($objectA->getProperty1(), $objectA->getProperty2());
         $this->property3 = $p3;
       }
    }
    $a = new A('p1','p2');
    $b = new B($a,'p3');

See it live here: http://sandbox.onlinephpfunctions.com/code/705bf1827da2bdf10f8d961ee1cb6fbdd88bc663

As an alternative, you could use __call magic method to forward all cals to class A:

<?php
 class A {
       private $property1;
       private $property2;
       public function __construct($p1,$p2){
          $this->property1 = $p1;
          $this->property2 = $p2;
       }

    }

    class B extends A {
       private $property3;
       private $a;
       public function __construct($objectA,$p3){
         $this->a = $objectA;
         $this->property3 = $p3;
       }

       public function __call($name, $arguments)
       {
          return call_user_func_array(array($this->a, $name), $arguments);
       }
    }
    $a = new A('p1','p2');
    $b = new B($a,'p3');
Constantin Galbenu
  • 16,951
  • 3
  • 38
  • 54
  • 1
    Or, you could make property1 and property2 protected and you don't need the additional getters – Constantin Galbenu Jan 31 '17 at 13:10
  • Yes thanks that's a good input, but in my real case I have much more properties in class A (that don't get all set through class A constructor). In fact there are plenty of other properties, that's why I would like to be able to resume it to '$this = ' in my extended class. You get points but not full answer validation. – nyluje Jan 31 '17 at 13:18
  • @nyluje - There is no built in way to do what you are trying to do. Which is a good indication that maybe you should use an alternative design. If you really feel you need this then I suppose you could use reflection to access the properties directly. But even the statement "there are plenty of other properties" is a bit of a red flag. – Cerad Jan 31 '17 at 13:58
1

Based on how to clone object to child class in php

Using get_object_vars on the parent object, you can get an array of properties keys and values. You can then loop through them and assign them to the child object:

<?php
 class A {
       protected $property1;
       protected $property2;
       public function __construct($p1,$p2){
          $this->property1 = $p1;
          $this->property2 = $p2;
       }

    }

    class B extends A {
       private $property3;
       public function __construct($objectA,$p3){
         //$this = $objectA;
        $objValues = get_object_vars($objectA); // return array of object values
        foreach($objValues AS $key=>$value)
        {
             $this->$key = $value;
        }
        $this->property3 = $p3;
        echo $this->property1;
       }
    }
    $a = new A('p1','p2');
    $b = new B($a,'p3');

This does not work with private properties, they need to be at least of protected level.

Community
  • 1
  • 1
Antony
  • 1,253
  • 11
  • 19
0

I ended up managing it like that:

class B extends A{
    public function __construct($objectA){
        foreach($this as $k => $v){
            if(isset($objectA->{$k})){
                $this->{$k} = &$objectA->{$k};
            }
        }
    }
}

Compare to @Antony answer, notice it has & in front of $objectA->{$k}: $this->{$k} = &$objectA->{$k};. As I understood it, with &, any change on $objectB of properties belonging to the extended class A applies to $objectA.

I am aware it is not perfect and quite hacky but it does the job I need. Thanks for the input given by everybody.

nyluje
  • 3,573
  • 7
  • 37
  • 67
  • 1
    You are right, as passing the data using `&` passes it by reference. Instead of keeping a copy of the value, the property keeps a reference to the original object. Also note that you could use $objectA instead of $this in the foreach loop, skipping the isset requirement. – Antony Jan 31 '17 at 17:02
  • I do not like this as it forces you to make properties from A protected and does not feel right. – Constantin Galbenu Feb 01 '17 at 07:35