3

I have the following three classes:

class a
{ public $test; }

class b extends a { }
class c extends a
{
    function return_instance_of_b() { }
}

As you can see, both classes b and c derive from a. In the return_instance_of_b() function in c, I want to return an instance of the class b. Basically return new b(); with one additional restriction:

I need the data from the base class (a) to be copied into the instance of b that is returned. How would I go about doing that? Perhaps some variant of the clone keyword?

Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
  • Perhaps this question about [How to Cast Objects in PHP5](http://stackoverflow.com/questions/2226103/how-to-cast-objects-in-php) would be of interest to you. – Rusty Fausak Sep 22 '11 at 05:49
  • When you do `return new b();`, the variables from base class `a` are available, since they inherit from class `a`, but there will be no data set in them (unless they're set in the constructor of class `a` or `b`. Where is the data supposed to come from? Should the new object for class `b` have the data copied from the current `c` object? – nickb Sep 22 '11 at 06:17
  • @nickb: Yeah, I would like the data from the base class copied from the current instance of `c` to the new instance of `b`. – Nathan Osman Sep 22 '11 at 06:43
  • @GeorgeEdison: See my answer below, I believe it achieves what you are looking for. – nickb Sep 22 '11 at 06:53
  • @GeorgeEdison this seems to be a bit smelly design. Why does `c` need to know that `b` exists? They should be substitutable (LSP). – chelmertz Sep 22 '11 at 08:08

2 Answers2

2

You can use the get_class_vars function to retrieve the names of the variables you want to copy, and just loop to copy them.

The variables that are defined are protected so they are visible to get_class_vars in its scope (since c extends a), but not directly accessible outside the class. You can change them to public, but private will hide those variables from get_class_vars.

<?php
class a
{ 
    protected $var1;
    protected $var2;
}

class b extends a 
{
}

class c extends a
{
    function __construct()
    {
        $this->var1 = "Test";
        $this->var2 = "Data";
    }

    function return_instance_of_b() 
    {
        $b = new b();
        // Note: get_class_vars is scope-dependant - It will not return variables not visible in the current scope
        foreach( get_class_vars( 'a') as $name => $value) {
            $b->$name = $this->$name;
        }
        return $b;
    }
}

$c = new c();
$b = $c->return_instance_of_b();
var_dump( $b); // $b->var1 = "Test", $b->var2 = "Data
nickb
  • 59,313
  • 13
  • 108
  • 143
0

I believe you can achieve this with some reflection. Not very pretty code, I'm sure there is a much more succinct method to achieve this but here you go.

class a
{ 
    public $foo;
    public $bar;

    function set($key, $value) {
        $this->$key = $value;
    }

    function get($key) {
        return $this->$key;
    }
}

class b extends a 
{ 
    function hello() {
        printf('%s | %s', $this->foo, $this->bar);
    }
}
class c extends a
{   
    public $ignored;

    function return_instance_of_b() {
    $b = new b();
    $reflection = new ReflectionClass($this);
    $parent = $reflection->getParentClass();
    foreach($parent->getProperties() as $property) {
        $key = $property->getName();
        $value = $property->getValue($this);
        $b->$key = $value;
    }

    return $b;
    }
}

$c = new c();
$c->set('foo', 'bar');
$c->set('bar', 'bar2');
$c->set('ignored', 'should be!');

$b = $c->return_instance_of_b();
$b->hello();
// outputs bar | bar2

Additionally you could use nickb's answer but instead of hard coding the class you could use get_parent_class

function return_instance_of_b() 
    {
        $b = new b();
        foreach(get_class_vars(get_parent_class(__CLASS__)) as $name => $value) {
            $b->$name = $this->$name;
        }
        return $b;
    }
Stoosh
  • 2,408
  • 2
  • 18
  • 24