2

Given:

  • class X extends A
  • class Y extends A

I have an Object of Class X and want to create an Object of Class Y that shares all fields with the Object of Class X (no matter if deep or shallow copy) that they have in common through Class A.

Can I cast Objects of Class X to Class Y or somehow else copy all attributes they have in common?

Prix
  • 19,417
  • 15
  • 73
  • 132
Lokomotywa
  • 2,624
  • 8
  • 44
  • 73
  • What is the final point? – Royal Bg Feb 12 '14 at 16:45
  • 1
    possible duplicate of [How to Cast Objects in PHP](http://stackoverflow.com/questions/2226103/how-to-cast-objects-in-php) – Eternal1 Feb 12 '14 at 16:45
  • Unless you type-hint, then anything is possible. If you type-hint X, then Y is not compatible. Casting won't work, though if there's still a common interface then maybe you can have them both implement an interface as well as extend A..? A lot of options. It'll depend on your particular case. Can you provide a most specific example? – Rob Baillie Feb 12 '14 at 16:46
  • Thanks for the additional info and clarification, but why do you need a copy? – Rob Baillie Feb 12 '14 at 16:50
  • @TwiStar, No duplicate, the objects are related by common superclass – Lokomotywa Feb 12 '14 at 16:51
  • @RobBaille The framework I am working with wants me to use class Y – Lokomotywa Feb 12 '14 at 16:52
  • Can't you set the object "Y" to a private property of class X, so one can use it? Or even to the super class? – Royal Bg Feb 12 '14 at 16:53
  • what would that help? I want the values of object x to be copied to their corresponding fields object y (which I could do manually, I know). – Lokomotywa Feb 12 '14 at 16:56
  • you can do a little hack and assign all `get_object_vars` from one to another – Royal Bg Feb 12 '14 at 16:58
  • Its more like multiple inheritance and which is not allowed in PHP however it could be achieved via interface and PHP 5.4.0 Trait http://php.net/manual/en/language.oop5.traits.php – Abhik Chakraborty Feb 12 '14 at 17:04

1 Answers1

0

If you would have simply asked: how can I easily create a variable of class Y that has all the common contents of class A of a variable of class X? Then I think you would have gotten a quicker answer. However you asked a question about casting.

Casting is a way of 'tricking' the compiler (or in this case the interpreter) to interpret a variable of one type as a variable of another type. If you know what you are doing this can come in handy sometimes. Most of the time however, it is a bad idea.

Casting to objects is not possible in PHP, but if it were and you could write:

class A {
  public $foo = 1;  
}
class X extends A {
  public $bar  = "2";
}

class Y extends A {
  public $bom = 3;
}

$x = new X();
$y = (Y) x;

Would you want PHP to think variable $y is of type Y or would you want it to actually be of type Y? The above would achieve the first, not the latter. As soon as you would access $y->bom your program's execution would run into a problem, since no memory was allocated for $bom nor was it initialized. In languages that do allow t his, like c++, this would likely cause a GPF.

Therefore you don't need to cast, you don't want to cast and you can't cast to begin with. Forget casting :)

What you want to do is create some method that copies the fields of another object to your object instance. Here is an example:

class A {
  public $foo;  

  public function copy($cA) {
    $this->foo = $cA->foo;
  }
}
class X extends A {
  public $bar;

  public function copy($cX) {
    if ($cX instanceof A) parent::copy($cX);
    if ($cX instanceof X) {
      $this->bar = $cX->bar;
    }
  }
}
class Y extends A {
  public $bom;

  public function copy($cY) {
    if ($cY instanceof A) parent::copy($cY);
    if ($cY instanceof Y) {
      $this->bom = $cY->bom;
    }
  }
}

$x = new X();
$x->foo = "hello";
$x->bar = "world";

$otherX = new X();
$otherX->copy($x);
echo "$otherX->foo $otherX->bar \n"; // hello world 

$y = new Y();
$y->copy($otherX);
echo "$y->foo \n"; // hello

The method of copying in this example is by assignment. This is not very flexible though, since this means everytime you add a property or rename a property in one of these classes you'd have to update the copy method to reflect the change.

Here is a more flexible way of achieving the same thing:

class A {
  protected $foo;  

  public function copy($cA) {
    foreach (get_object_vars($cA) as $key => $value) {
      $this->$key = $value;
    }
  }

  public function setFoo($foo) {
    $this->foo = $foo;
  }
}
class X extends A {
  public $bar;

  public function out() {
    echo "$this->foo $this->bar \n";
  }
}
class Y extends A {
  public $bom;

  public function out() {
    echo "$this->foo $this->bom \n";
  }
}

// setup x
$x = new X();
$x->setFoo("hello");
$x->bar  = "world";

// setup otherX
$otherX = new X();
$otherX->copy($x);

$x->setFoo("hi"); 

$otherX->out(); // -> hello world

// setup Y
$y = new Y();
$y->copy($x);
$y->bom = "php";

$y->out();     // -> hi php

Though this method is a lot more flexible it is also somewhat crude.

echo $y->bar; // has become "world"

This happens because get_object_vars doesn't look at what variables each class type can have. You could work around this to some extent using ReflectionClass, but I am guessing by this time you've gotten the answer you needed.

Hope this helps.

Good luck!

Community
  • 1
  • 1
Lodewijk Bogaards
  • 19,777
  • 3
  • 28
  • 52