2

Disclaimer: This is not homework. Also, I'm describing a simplified situation so bear with my semi-psudo code.

I have what I feel is a pretty standard OOP situation, but I'm not sure the best way to handle it. Let's say I have 3 classes: Base, A, and B. Class A extends Base and B extends A. The Base class's constructor performs a database query that pulls various meta data defined in an array. See below:

Class Base {

    public $meta_data = array('col1','col2');

    function __construct() {
        $db->query("select ".join(',',$this->meta_data)." from table");
    }

}

Class A extends Base {

    public $meta_data = array('col3','col4');

    function _construct() {
        parent::__construct();
    }

}

Class B extends A {

    public $meta_data = array('col5','col6');

    function _construct() {
        parent::__construct();
    }

}

When I create a new B() object, I want the Base constructor's sql query to look like this:

select col1, col2, col3, col4, col5, col6 from table;

And when I create a new Base() object, I want the sql query to look like this:

select col1, col2 from table;

Now...I technically know how to accomplish this (in possibly a crude way) but I'm curious what the proper way is without too much code replication and keeping in mind flexibility for the future (ie, adding a subclass of B). I basically need to merge the $meta_data arrays on each inheritance level all the way up to the constructor in the Base class.

Any ideas?

2
  • Since each generation of your object has the same attribute, you'd have to do your parent attribue merging in the constructor. PHP does not allow an object attribute to be initialized to anything other than a constant value, so public $meta = array_merge(parent::$meta, ...) is not possible. Commented Feb 3, 2012 at 3:31
  • composition pattern would be better. Commented Feb 3, 2012 at 4:09

3 Answers 3

3

When you extend the class and define the new property you are overriding the values set in the parent class. I would wind up removing the $meta_data array from all but Base. Then in your extending classes create a function similar to:

After solving it in a very simple way I wound up deciding I would go with something like the following in Base:

protected function addToMetaData(array $meta_data) {
    $this->meta_data = array_merge($this->meta_data, $meta_data);
}

Then in your extending class constructors you just pass in an array of the values you want to add to Base::$meta_data.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the input...I'm thinking about using something similar to your idea. It's nice and elegant.
0
class base
{
    public $met;

    function __construct()
    {
    $this->met=array("col1","col2");
//      $this->query= "select " . $this->met " from test"; 
    }
}

class a extends base
{

    public $meta;
    function __construct()
    {
        parent::__construct();
            $this->meta =array("col3", "col4" );
        $this->meta=array_merge((array)$this->meta,(array)$this->met);
        print_r($this->meta);
    }

}

class b extends a
{
public $metb;
    function __construct()
    {
        parent::__construct();
            $this->metb =array("col5", "col6" );
        $this->metb=array_merge((array)$this->meta,(array)$this->met);
        print_r($this->metb);
    }
}

Comments

0

You can build the list in the constructor as well if you use static definitions:

class Base {
    public static $meta_data = array('col1','col2');
    function __construct() {
        $this->meta_data = array();
        $class = $this;
        while ($class) {
            $this->meta_data = array_merge($class::$meta_data, $this->meta_data);
            $class = get_parent_class($class);
        }
        print implode(',', $this->meta_data) . "\n";
    }
}

class A extends Base {
    public static $meta_data = array('col3','col4');
}

class B extends A {
    public static $meta_data = array('col5','col6');
}

new A();
new B();

This will output:

col1,col2,col3,col4
col1,col2,col3,col4,col5,col6

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.