Álvaro González
Álvaro González

Reputation: 146660

Fetch parent class data from static method

In an existing code base, I have a static builder method that returns an instance. Here's a simplified example:

class Grandparent{
}

class Parent extends Grandparent{
}

class Child extends Parent{
    public static fetchChildById($id){
        // ...
        return new Child;
    }
}

In real code I have a single Grandparent class and several subclasses similar to Parent and Child (not just Parent and Child).

I now need to implement a new method at Grandparent to be used at fetchChildById(). Such method needs to make use of certain piece of data that's common to all children from the same parent. Since I don't have a class instance yet I'm forced to make everything static but, of course, that won't work properly because it isn't possible to overrite static properties and methods:

class Grandparent{
    protected static $data = array(
        'default',
    );

    protected static function filter(){
        foreach(self::$data as $i){ // <!-- Will always be `default'
            // ...
        }
    }
}

class Parent extends Grandparent{
    protected static $data = array(
        'one',
        'two',
    );
}

class Child extends Parent{
    public static fetchChildById($id){
        self::filter();
        // ...
        return new Child;
    }
}

I believe it's a use case for late static binding but code needs to run on PHP/5.2.0 :(

I'm not very fond of the obvious workarounds I've thought about:

Am I overlooking some obvious mechanism to customize $data?

Upvotes: 0

Views: 147

Answers (1)

Jon
Jon

Reputation: 437854

Here's an alternative using reflection. It will require modification of all fetchChildById implementations, but it's trivial enough to be done with global find/replace:

self::filter(__CLASS__); // this is the modification

Then filter would become:

protected static function filter($className){
    $reflect = new ReflectionClass($className);
    $data = $reflect->getStaticPropertyValue('data');
    foreach($data as $i){
        // ...
    }
}

Update: The property $data needs to be public for the above to work (apologies -- I wrote public during exploration). But there's an equivalent version that doesn't have this requirement:

$reflect = new ReflectionProperty($className, 'data');
$reflect->setAccessible(true);
$data = $reflect->getValue();

Upvotes: 1

Related Questions