Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge array property of descendant objects

I have a following class hierarchy, which shown in a reproduction script below:

<?php
header('Content-Type: text/plain');

class A
    {
        public $config = array(
            'param1' => 1,
            'param2' => 2
        );

        public function __construct(array $config = null){
            $this->config = (object)(empty($config) ? $this->config : array_merge($this->config, $config));
        }
    }

class B extends A
    {
        public $config = array(
            'param3' => 1
        );

        public function __construct(array $config = null){
            parent::__construct($config);

            // other actions
        }
    }

$test = new B();

var_dump($test);
?>

Output:

object(B)#1 (1) {
  ["config"]=>
  object(stdClass)#2 (1) {
    ["param3"]=>
    int(1)
  }
}

What I wanted, is that A::$config not be overriden by B::$config. There might be a lot of descendant classes from B, where I would like to change $config, but I need that those $config values to merge / overwrite if match $config values of all it's parents.

Q: How can I do that ?

I've tried to use array_merge() but in non-static mode those variables just override themselves. Is there a way to achieve merge effect for class tree without static (late static binding) ?

like image 813
BlitZ Avatar asked Feb 01 '26 04:02

BlitZ


2 Answers

Instead of declaring a $config property with values that you're going to change in the constructor, it's better to declare those values as default values. This is also described in Orangepill's answer:

class A
{
    public $config;

    private $defaults = array(
        'param1' => 1,
        'param2' => 2,
    );

    public function __construct(array $config = array())
    {
        $this->config = (object)($config + $this->defaults);
    }
}

A few twists there; by declaring the default value of the $config constructor argument as an empty array, you can simplify your code by using array operators like I did above. Undefined keys in $config are filled in by $this->defaults.

The extended class will look very similar:

class B extends A
{
    private $defaults = array(
        'param3' => 1
    );

    public function __construct(array $config = array())
    {
        parent::__construct($config + $this->defaults);
    }
}
like image 181
Ja͢ck Avatar answered Feb 03 '26 20:02

Ja͢ck


You can restructure how your extended class is instantiated

class B extends A
{
    private $defaults = array('param3' => 1);
    public function __construct(array $config = null){
        parent::__construct($config?array_merge($this->defaults, $config):$this->defaults);
    }
}
like image 27
Orangepill Avatar answered Feb 03 '26 18:02

Orangepill



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!