Kürzlich habe ich einem Freund geholfen, Code zu verstehen und so zu ändern, dass er gut mit asynchronen Aufrufen ans Backend funktioniert. Ein Bonus wäre, ihn modularer und wiederverwendbarer schreiben zu können.

Der Code ist ein WordPress-Plugin, das mit einem sehr altmodischen Ansatz geschrieben wurde – Business- und Frontend-Logik an einer Stelle vermischt. Datenmanipulationen mitten im Template-Code und so weiter.

Im Grunde das, was man Anfang der 2000er auf PHP-Seiten gesehen hat, bevor all die großartigen OOP-Erweiterungen in die Sprache kamen und es eine Reihe ausgereifter Frameworks gab.

Der Fall, an dem ich heute geknabbert habe, sah so aus: Du hast eine Tabelle, die eine Menge Einträge anzeigt. Wir mussten der Tabelle mehrere Filter hinzufügen und sie per AJAX funktionieren lassen, damit sich die Oberfläche schnell aktualisiert, ohne die ganze WordPress-Admin-Seite neu zu laden.

Das Filtern der Daten war einfach – ein schnelles Inline-array_filter, um die Daten zu filtern, bevor sie an den Template-Code übergeben wurden (um den Code-Stil beizubehalten, stand das ebenfalls in der Template-Datei 😇).

Das Problem begann, als wir daran gingen, die Tabelle über AJAX renderbar zu machen.

Sie steckt mitten in einem Haufen anderen Template- und Business-Codes. Wenn wir die Ausgabe per AJAX nur auf die Tabelle beschränken wollten, hatten wir nur ein paar Möglichkeiten.

Die erste wäre, das HTML vor und nach der Tabelle in RIESIGE if-Anweisungen zu packen, damit es nicht gerendert wird.

Eine andere wäre, das Template in eine separate Datei auszulagern und sie in der AJAX-Action einzubinden, die wir im Code des Plugins definieren würden.

Anonyme Funktionen to the rescue!

Als ich überlegte, wie sich das am einfachsten lösen lässt, versuchte ich, eine normale PHP-Funktion zu definieren, die den Tabellencode enthält, aber da gab es ein Problem.

Der Code läuft innerhalb einer Klassenmethode. Im Tabellen-Template gibt es Verweise auf $this. Wenn wir den Code nicht zu sehr ändern wollen, müssten wir $this als Funktionsargument übergeben. Tja, das funktioniert nicht so ganz, denn $this kann man nicht als Parameter übergeben 🤷‍♂️.

Ich war ein bisschen enttäuscht, dass wir einen Haufen im Template umschreiben müssten, und es gab ziemlich viele Verweise, die wir im Blick behalten wollten, damit alles weiter funktioniert.

Dann fiel mir ein, dass die Seite nicht auf PHP 5.2 läuft, sondern auf PHP 7 und anonyme Funktionen somit unterstützt würden.

Und die haben dieses praktische Feature, mit dem man festlegen kann, welche Variablen aus dem aufrufenden Scope an die Funktion weitergereicht werden, wenn sie aufgerufen wird. Zum Beispiel:

$table_function = function() use ( $pages, $current_page, $items ) {
    // ... Table render code
}

Dadurch kannst du direkt im Funktionskörper auf $pages oder $items zugreifen.

Das Großartige daran: Du kannst auch $this als Variable in den Funktions-Scope übergeben!

Jetzt konnten wir den Code zum Rendern der Tabelle komplett in eine separate Funktion auslagern, die wir beim AJAX-Aufruf isoliert aufrufen können!

Natürlich muss man bei den Variablen im Funktionskörper sehr vorsichtig sein, da sie definiert sein müssen. Man sollte also genau darauf achten, wo die AJAX-Funktion aufgerufen werden kann.

Für uns bedeutet das, dass wir in der Hauptklasse eine winzige Action hinzufügen, die die Datei weiterhin einbindet, wir aber mehr Kontrolle darüber haben, alle anderen Ausgaben zu unterbinden, die sonst stattfinden würden.