Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static inheritance of array

It is kind of hard for me to explain what I am trying to do so I will just provide 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 possible at all?

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 which can be maximum 10 symbols, I define this in the user class' rules and then all user objects will obey the rule when their property name is about to be changed. The rules array is static because they apply to all objects of this class. However when I inherit it for example in a VIP user then the VIP will need to have additional rules for properties that the basic user doesn't have. I need to be able to extend the rules array but if I define such an array in the child class it just overwrites the parent rules which I also need.

like image 330
Emilio Rodrigues Avatar asked Nov 27 '25 10:11

Emilio Rodrigues


2 Answers

So yes, there is a way to do it with only 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 here.

If order matters, then change merge arguments order (right now it will be like it is in class hierarchy chain - from child to parent)

Or, utilize 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 here. This is even shorter way. So it can be done with plain array mapping. Unfortunately, current class has to be added manually to the iterated hierarchy array.

like image 51
Alma Do Avatar answered Nov 29 '25 23:11

Alma Do


This will achieve what you want

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

though there's probably a slightly cleaner way of doing it defining getData() only in class A

like image 32
Mark Baker Avatar answered Nov 29 '25 23:11

Mark Baker