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 derRating
-Klasse verbunden. Möchte man den Autor um eine weitere Klasseneigenschaft erweitern, muss man auch die KlasseRating
erweitern. Das ist speziell dann von großem Nachteil, wenn das WordPress Plugin recht groß ist und es viele Vorkommen vonRating
gibt. - Unit Tests für die
Rating
-Klasse erfordern, dass auch gleichzeitig dieAuthor
-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ötigtAuthor
.Rating
erzeugtAuthor
.Rating
ruftAuthor
auf.Author
benötigtDateTime
.Author
erzeugtDateTime
.Author
ruftDateTime
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:
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:
Schauen wir uns das ganze in einem Real-World-WordPress-Plugin an.