21.1. Dependency Injection in WordPress

Wie im vorherigen Artikel zur Objektorientierung (OOP) in WordPress erwähnt, möchte ich mich nun auf die Dependency Injection als Entwurfsmuster für WordPress-Projekte fokussieren.

Mittels Dependency Injection ist es möglich, die Verantwortlichkeit zum Aufbau einer Abhängigkeit zwischen Objekten in eine zentrale Komponente zu überführen. Das macht vor allem dann Sinn, wenn ein WordPress Plugin extrem gewachsen ist oder in der Zukunft wachsen soll.

Anders gesagt verlangt das Entwurfsmuster von uns, dass wir ein System schaffen, welches Abhängigkeiten innerhalb von Klassen handhabt.

Hört sich kompliziert an? Man kann letztlich alles kompliziert beschreiben. Aber sehen wir uns gleich dazu ein Beispiel an.

Zuvor möchte ich noch erwähnen, dass Dependency Injection kein Allheilmittel ist. Niemand soll gezwungen sein, dieses (oder andere) Entwurfsmuster zu nutzen. Niemand wird dadurch ein besser oder schlechterer Entwickler (siehe dazu auch Dependency Injection is Evil).

Nun aber zum Beispiel:

Ohne Dependency Injection

In der „alten“ Schreibweise würde man so vorgehen:

<?php
class Rating
{
    private $value;

    private $author;

    public function __construct(int $value, string $authorFirstName, string $authorLastName)
    {
        $this->value = $value;
        $this->author = new Author($authorFirstName, $authorLastName);
    }
}

class Author
{
    private $firstName;

    private $lastName;

    public function __construct(string $firstName, string $lastName)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }
}

Beim Anlegen eines neuen Rating-Objekts müsste man die Daten für den Autor übergeben, weil in der Rating-Klasse ein neues Objekt der Klasse Author erzeugt wird:

<?php
$rating = new Rating(4, "Florian", "Simeth");

Daran ist nichts falsch. Es könnten sich aber mehrere Probleme ergeben:

  • Die Daten über den Autor haben in der Rating-Klasse eigentlich nichts verloren.
  • Die Author-Klasse ist sehr eng mit der Rating-Klasse verbunden. Möchte man den Autor um eine weitere Klasseneigenschaft erweitern, muss man auch die Klasse Rating erweitern. Das ist speziell dann von großem Nachteil, wenn das WordPress Plugin recht groß ist und es viele Vorkommen von Rating gibt.
  • Unit Tests für die Rating-Klasse erfordern, dass auch gleichzeitig die Author-Klasse getestet wird.
  • Es entsteht eine Art Hierarchie, die mit jeder Klasse und jedem Objekt tiefer wird. Die Website php-di.org beschreibt diese Situation ziemlich gut. Und zwar wie folgt:

Würden wir das Plugin noch einmal erweitern, wird’s schon ganz schön kompliziert obwohl wir nur drei Klassen haben, nämlich Rating, Author und DateTime:

class Rating
{
    private $value;

    private $author;

    public function __construct(int $value, string $authorFirstName, string $authorLastName, string $birthDate)
    {
        $this->value = $value;
        $this->author = new Author($authorFirstName, $authorLastName, $birthDate);
    }
}

class Author
{
    private $firstName;

    private $lastName;

    private $birth;

    public function __construct(string $firstName, string $lastName, string $birthDate)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->birth = new DateTime($birthDate);
    }
}
  • Das Plugin benötigt Rating.
  • Plugin erzeugt Rating.
  • Plugin ruft Rating auf.
    • Rating benötigt Author.
    • Rating erzeugt Author.
    • Rating ruft Author auf.
      • Author benötigt DateTime.
      • Author erzeugt DateTime.
      • Author ruft DateTime auf.

Mit Dependency Injection

Möchten wir nun alle Probleme von oben ausmerzen, könnten wir die Dependency Injection in unseren WordPress Projekten nutzen. Und das könnte so aussehen:

You’re not allowed to see this content. Please log in first.

Dependency Inversion

Nehmen wir an, wir wollen zwischen einem angemeldetem und einem nicht-angemeldetem Nutzer unterscheiden. Wir können das ganz einfach tun indem wir die Klasse Author als abstrakt deklarieren und zwei neue Klassen erstellen die davon abhängig sind:

You’re not allowed to see this content. Please log in first.

Schauen wir uns das ganze in einem Real-World-WordPress-Plugin an.