Static array inheritance

I find it difficult to explain what I am trying to do, so I will just give an example

class A {
    static $data = ['a'];

    static function getData() { return static::$data; }
}

class B extends A {
    static $data = ['b'];
}

class C extends B {
    static $data = ['c'];
}

class D extends B {
    static $data = ['d'];
}

$a = new A;
$b = new B;
$c = new C;
$d = new D;

$a::getData(); // Output: Array('a'), Expected: Array('a');
$b::getData(); // Output: Array('b'), Expected: Array('a', 'b');
$c::getData(); // Output: Array('c'), Expected: Array('a', 'b', 'c');
$c::getData(); // Output: Array('d'), Expected: Array('a', 'b', 'd');

      

Is this even possible?

EDIT : I have my data objects and each object has a set of rules for its properties. For example, a User object has a property name

that can be no more than 10 characters, I define this in the custom class rules, and then all custom objects will obey the rule when its property name

is changed. The rules array is static because it applies to all objects of this class. However, when I inherit it from, for example, a VIP user, then the VIP will need to have additional rules for properties that the base user does not have. I need to be able to expand the rules array, but if I define such an array in a child class, it just overwrites the parent rules, which I need as well.

+3


source to share


3 answers


So yes, there is a way to do it just with the parent class method :

class A
{
    public static $data = ['a'];

    public static function getData()
    {
        $result = static::$data;
        $class  = get_called_class();
        while ($class = get_parent_class($class)) {
            $result = array_merge($result, $class::$data);
        }

        return $result;  
    }
}

class B extends A 
{
    public static $data = ['b']; 
}

class C extends B 
{
    public static $data = ['c']; 
}

class D extends C 
{
    public static $data = ['d']; 
}

      

Demo is here .

If order matters, then change the order of the merge arguments (right now it will look like a chain of a class hierarchy - from child to parent)



Or use class_parents()

class A
{
    public static $data = ['a'];

    public static function getData()
    {
        $classes  = [get_called_class()]; //no class with name "0"
        $classes += class_parents($classes[0]);
        return call_user_func_array('array_merge', 
            array_map(
                function($class) {
                    return $class::$data;
                }, 
                $classes
            )
        );
    }
}

      

Demo is here . This is an even shorter route. So it can be done with a simple array mapping. Unfortunately, the current class has to be manually added to the iterated array of the hierarchy.

+2


source


This will achieve the desired

class A {
    static $data = ['a'];

    static function getData() { return self::$data; }
}

class B extends A {
    static $data = ['b'];

    static function getData() { return array_merge(parent::getData(), self::$data); }
}

class C extends B {
    static $data = ['c'];

    static function getData() { return array_merge(parent::getData(), self::$data); }
}

class D extends B {
    static $data = ['d'];

    static function getData() { return array_merge(parent::getData(), self::$data); }
}

$a = new A;
$b = new B;
$c = new C;
$d = new D;

var_dump($a::getData()); // Array('a');
var_dump($b::getData()); // Array('a', 'b');
var_dump($c::getData()); // Array('a', 'b', 'c');
var_dump($d::getData()); // Array('a', 'b', 'd');

      



Demo

although there is probably a slightly cleaner way of doing this by defining getData () only in class A

+2


source


You want to concatenate arrays, but in your example code you will never specify that. The call get_parent_class(get_called_class())

gets the parent class or false if it doesn't exist.

Also, you cannot use self

, but you must use static

if you want to use the value of the actual class that was called. self

will always use the same value.

class A {
    static $data = ['a'];

    static function getData() {
        $parent = get_parent_class(get_called_class());
        if(method_exists($parent, 'getData')) {
            return array_merge($parent::getData(), static::$data);
        } else {
            return static::$data;
        }
    }
}
// other classes unchanged

      

+2


source







All Articles