Traits in PHP 5.4

Werbung

Traits? Nein, das sind die nicht kleinen Schokoladenkügelchen. Traits sind eine der neuen Funktionen in PHP 5.4.

Dies alleine wäre noch keine Meldung wert, sondern die Tatsache, dass Code Wiederverwendbarkeit in PHP wieder einen Schritt weiter ist.

Aber wie funktioniert Traits in PHP 5.4?

In jedem Buch über PHP Programmierung, aber nicht nur dort, steht früher oder später etwas von Code Wiederverwendbarkeit oder Reusability. Das hört sich immer sehr schön und einfach an, aber das ist es in der Realität leider nicht.

In PHP sind Mehrfachvererbungen nicht möglich. Also

class classA extends classB extends classC

funktioniert also nicht.

Inhaltsverzeichnis

Traits sind keine Schokoladenkügelchen

Wie aber können mir Traits bei der Programmierung in PHP helfen? Ich habe mir hier mal ein Beispiel ausgedacht. Ein sogenanntes Real World Example.

Also, in meinem Beispiel schreiben wir eine Anwendung für einen Blumenladen. In dieser Anwendung gibt es Produkte wie Blumen (Rosen und Tulpen) und Behälter (Vasen, Kübel).

Bevor man sich an eine neue Anwendung macht, versucht man in der Regel gleichartige Objekte so weit wie möglich runterzubrechen.

Hier meine drei Klassen für die Blumen:

class Blume
{
    protected $_farbe;
    protected $_laenge;

    public function setFarbe($farbe)
    {
        $this->_farbe = $farbe;
    }

    public function getFarbe()
    {
        return $this->_farbe;
    }

    public function setLaenge($laenge)
    {
        $this->_laenge = $laenge;
    }

    public function getLaenge()
    {
        return $this->_laenge;
    }
}
class Tulpe extends Blumen
{
    public function __construct($farbe, $laenge)
    {
        $this->_farbe = $farbe;
        $this->_laenge = $laenge;
    }
}
class Rose extends Blumen
{
    public function __construct($farbe, $laenge)
    {
        $this->_farbe = $farbe;
        $this->_laenge = $laenge;
    }
}

So, jetzt mache ich mich an die Behälter, also Vasen und Kübel.

class Behaelter
{
    protected $_farbe;
    protected $_hoehe;

    public function setFarbe($farbe)
    {
        $this->_farbe = $farbe;
    }

    public function getFarbe()
    {
        return $this->_farbe;
    }

    public function setHoehe($hoehe)
    {
        $this->_hoehe = $hoehe;
    }

    public function getHoehe()
    {
        return $this->_hoehe;
    }
}
class Vase extends Behaelter
{
    public function __construct($farbe, $hoehe)
    {
        $this->_farbe = $farbe;
        $this->_hoehe = $hoehe;
    }
}
class Kuebel extends Behaelter
{
    public function __construct($farbe, $hoehe)
    {
        $this->_farbe = $farbe;
        $this->_hoehe = $hoehe;
    }
}

Und jetzt fällt mir etwas auf. Auch Vasen und Kübel haben eine Farbe, aber keine Länge, sondern eine Höhe. Da es auch nicht passen würde, kann ich Vasen und Kübel nicht von Blume ableiten. Hier hilft die Traits Funktion.

Werbung

So könnte das aussehen mit Hilfe von Traits:

trait Farbe
{
    protected $_farbe;

    public function setFarbe($farbe)
    {
        $this->_farbe = $farbe;
    }

    public function getFarbe()
    {
        return $this>_farbe;
    }
}
class Blume
{

    use Farbe;
    protected $_laenge;

    public function setLaenge($laenge)
    {
        $this->_laenge = $laenge;
    }

    public function getLaenge()
    {
        return $this->_laenge;
    }
}
class Behaelter
{
    use Farbe;
    protected $_hoehe;

    public function setHoehe($hoehe)
    {
        $this->_hoehe = $hoehe;
    }

    public function getHoehe()
    {
        return $this->_hoehe;
    }
}

Was nicht da ist, kann nicht fehlerhaft sein

Die Klassen für die Tulpe, Rose, Vase und Kübel habe ich im Traits Beispiel weggelassen. Diese müssten natürlich trotzdem erstellt werden. Aber selbst in diesem kleinen Beispiel konnte ich bereits die beiden Methoden getFarbe() und setFarbe() zusammenfassen. In einer großen Anwendung kommen da hunderte Zeilen Code und unzählige Methoden zusammen, die nicht mehr doppelt geschrieben werden müssen. Und was nicht da ist, kann auch nicht fehlerhaft sein.

Und das Schöne an der Sache ist, man kann mehrere Traits benutzen. Also es könnte nicht nur den Trait „Farbe“ geben, sondern evtl. auch „Preis“. Das ist allerdings nur ein Beispiel und ob es Sinn ergibt, wird man während der Programmierung mit der neuen Funktion schon herausfinden.

Gleiche Methodennamen in unterschiedlichen Traits

Ein Problem bleibt noch falls es in zwei Traits, die ich benutzen will, zwei Methoden mit dem gleichen Namen gibt. Aber auch hier gibt es eine elegante Lösung. Insteadof und as sind die die Heilsbringer.

Auch hier ein Beispiel dazu:

trait Database
{
    public function save()
    {
        // Speichern in eine Datenbank
    }
}
trait CSV
{
    public function save()
    {
        // Speichern in eine CSV Datei
    }
}

Beispiel Insteadof: Hier wird die Datenbank save() Methode verwendet anstelle der (insteadof) CSV save() Methode.

class File
{
    use Database, CSV {
        Database:save insteadof CSV;
    }

    public function doSave()
    {
        $this->save();
    }
}

Beispiel as: Hier wird die CSV save() Methode anstelle der Database save() Methode verwendet. Allerdings wird für die Database save() Methode ein Alias erzeugt und daher ist es auch hier über den Alias verfügbar.

class File
{
    use Database, CSV {
        CSV:save instead of Database;
        Database:save as databaseSave;
    }

    public function doSave()
    {
        $this->save();
    }
}

Link: PHP Traits