Manchmal ist static etwas zu static

Posted by in PHP

Heute hatte ich einen interessanten Effekt in Bezug auf die Vererbung von statischen Klassenvariablen.

Gegeben sei folgende Klasse, welche einige Config-Daten halten soll:

abstract class Config
{
 
    private static $definitions = array();
 
    protected static function addDefinition ($key, $value)
    {
        self::$definitions[$key] = $value;
    }
 
    protected static function getDefinition ($key)
    {
        return self::$definitions[$key];
    }
}

Die Sicherheitsabfragen und Dokumentation habe ich zum einfacheren Verständniss mal entfernt. Dann haben wir zwei weitere Klassen, welche von unserer abstrakten Config klasse erben.

class Config_A extends Config
{
 
    public static function addA ($key, $value)
    {
        self::addDefinition($key, $value);
    }
 
    public static function getA ($key)
    {
        return self::getDefinition($key);
    }
}
 
class Config_B extends Config
{
 
    public static function addB ($key, $value)
    {
        self::addDefinition($key, $value);
    }
 
    public static function getB ($key)
    {
        return self::getDefinition($key);
    }
}

Nun bestücken wir unsere Klassen mal mit Daten:

Config_A::addA ('treiber', 'configA');
Config_B::addB ('treiber', 'configB');
 
echo Config_A::getA ('treiber');

Nun würde man erwarten, dass auch wieder ein ‚configA‘ heraus kommt. Da die statische Klassenvariable jedoch in der abstrakten Oberklasse liegt verwenden beide Unterklassen die selbe Variable. Die Ausgabe lautet nämlich: ‚configB‘.

Wie kann man das Dilema also Lösen? Mein erster Ansatz war: Wir verschieben die Variable in die Unterklassen.

abstract class Config
{
 
    protected static function addDefinition ($key, $value)
    {
        $definitions = self::getDefinitions();
        $definitions[$key] = $value;
    }
 
    protected static function getDefinition ($key)
    {
        $definitions = self::getDefinitions();
        return $definitions[$key];
    }
 
    abstract protected static function getDefinitions ();
}
 
class Config_A extends Config
{
    private static $definitions = array();
 
    protected static function getDefinitions()
    {
        return self::$definitions;
    }
 
    ...
}

Analog dazu wird Config_B implementiert.

Jedoch sind abstrakte statische Methoden nur in PHP 5.0.x und 5.1.x erlaubt. Eine weitere Lösung wäre es, aus den Klassen einfach Instanzklassen zu machen. Bei meinem Framework mag ich es jedoch lieber nicht so viele Objekte zum Konfigurieren umher zu jonglieren sondern einfach den Zustand des Systems mit einer statischen Klasse zu verändern.

Letztendlich habe ich folgende Lösung umgesetzt:

abstract class Config
{
 
    protected static $definitions = array();
 
    protected static function addDefinition ($class, $key, $value)
    {
        self::validateDefinitions($class);
        self::$definitions[$class][$key] = $value;
    }
 
    protected static function getDefinition ($class, $key)
    {
        self::validateDefinitions($class);
        return self::$definitions[$class][$key];
    }
 
    private static function validateDefinitions ($class)
    {
        if (! isset(self::$definitions[$class])) {
            self::$definitions[$class] = array();
        }
    }
 
}
 
class Config_A extends Config
{
 
    public static function addA ($key, $value)
    {
        self::addDefinition(__CLASS__, $key, $value);
    }
 
    public static function getA ($key)
    {
        return self::getDefinition(__CLASS__, $key);
    }
 
}