PHP: Abstrakte generische Klassen durch Late Static Bindings

*/–>

/*
@licstart The following is the entire license notice for the
JavaScript code in this tag.

Copyright (C) 2012 Free Software Foundation, Inc.

The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version. The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.

As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.

@licend The above is the entire license notice
for the JavaScript code in this tag.
*/
*///–>

Mit PHP 5.3 zog eine neue Fähigkeit in die Sprache ein, die sich
hinter einem alten Schlüsselwort verbirgt: static: Late Static
Bindings. Nun ist PHP 5.3 schon ein seit einigen Jahren stabil und
von 5.4 abgelöst, trotzdem ist diese Spracheigenschaft einen Artikel wert.

Statische Klasseneigenschaften werden in PHP klassisch mit self::
oder classname:: angesprochen. self:: bezieht sich dabei immer
auf die zur Compilezeit aktuelle Klasse, mithin die, aus der der
self:: Aufruf erfolgt.

Seit Version 5.3 besteht die Möglichkeit, statt mit self::
statische Eigenschaften mit static:: anzusprechen – die Auflösung
des Klassennamens erfolgt hier nicht zur Compilezeit sondern zur
Laufzeit – daher der Name ‚Late Static Bindings‘. Wir können diese
Eigenschaft nutzen, um einen Algorithmus abstrakt auszuprogrammieren —
in einer abstrakten Klasse – und dabei auf statische Eigenschaften
zugreifen, die in einer erbenden Klasse zu definieren sind.

Das erlaubt leicht zu erweiternde, wartbare und elegante
Implementierung, die vorher nur über Umwege oder umständliche
Formulierungen in PHP realisiert werden konnten.

Beispiel ‚Model‘

Zur Erklärung ein vereinfachter Ausschnitt einer Model
Implementierung.

  • Feldnamen/Properties

    Model_Abstract deklariert die geschützte Eigenschaft $_fields und den
    allgemeingültigen Fall der Überprüfung, ob ein übergebener Name ein
    gültiger Feldname ist.

    abstract class Model_Abstract 
    {
        /**
         * Valid field names
         * @var array
         */
        protected static $_fields = null;
    
        /**
         * is the fieldname valid?
         * @param string $name
         * @return boolean
         */
        protected function isFieldValid($name)
        {
            return array_search($name, static::$_fields) !== FALSE;
        }
    
    }
    

    Eine Konkretisierung von Model_Abstract muss nun lediglich die
    Liste gültiger Feldnamen definieren

    class Model_User extends Model_Abstract
    {
        protected static $_fields = new array(
            'id',
            'nickname',
            'given_name',
            'surname',
            [...]
        );
    }
    
    

    Wenn auf einer Model_User Instanz isFieldValid aufgerufen wird,
    wird zur Laufzeit static::$_fields zur Klasseneigenschaft von
    Model_User aufgelöst.

    Dabei ist die Implementierung von isFieldValid einfach zu lesen und
    zu verstehen, es gibt keine weiteren Methodenaufrufe; dies kann
    weiter gesponnen werden, bis Model_Abstract das gesamte generische
    Verhalten des Model-konzepts einer Anwendung implementiert —
    konkrete Implementierungen müssen nur die Feldnamen definieren und
    dem konkreten Model eigene Eigenschaften über die Propertybehandlung
    hinaus implementieren – was in den meisten Fällen nicht nötig sein wird.