Hallo allerseits!
Diesen Monat haben wir den ersten Satz des
Backend PHP Developer- Kurses abgeschlossen und stellen sie mit Macht und Kraft ein (so viel wie möglich in den Ferien). Der Kurs wurde mit einem anderen Lehrer ergänzt -
Evgeny Volosatov , den viele wahrscheinlich kennen. Nun, wir teilen traditionell interessante Dinge.
Lass uns gehen.
In jeder Anwendung gibt es Teile des Codes, die mehrere Teile der Architektur gleichzeitig „kreuzen“.
Dieses Problem ist bei der Arbeit mit einem voll funktionsfähigen Framework nicht so offensichtlich. Höchstwahrscheinlich ist Ihr Problem weit verbreitet, und es besteht die Möglichkeit, dass das Framework es bereits gelöst hat, indem es eine Aufteilung der Verantwortung opfert oder eine Abstraktion über dem Framework bereitstellt. Viele Frameworks verwenden eine ereignisorientierte Architektur, um End-to-End-Funktionsprobleme zu lösen. Es kommt jedoch immer ein Moment, in dem das Framework nicht in der Lage ist, das gewünschte Maß an Kontrolle über ein bestimmtes Stück Logik bereitzustellen. Dies gilt insbesondere bei Verwendung von Mikroframes oder bei der Entwicklung mit spezialisierten Bibliotheken. Je mehr Ihre Anwendung die Prinzipien der Aufgabentrennung berücksichtigt, desto größer ist die Rolle der End-to-End-Funktionalität in Ihrer Architektur.

Aspektorientierte PHP-Programmierung
Aspect Oriented Programming (AOP) ist ein Programmierparadigma, das sich auf die Organisation und Modularisierung von End-to-End-Funktionen konzentriert. Anwendungsfälle - ACLs, Protokollierung, Fehlerbehandlung, Caching.
Die in PHP integrierten (internen) Annahmen (wenn Sie eine Funktion / Konstante / Klasse definieren, bleibt diese für immer definiert) erschweren die Implementierung des AOP-Paradigmas.
Li3 war der erste, der das Problem der End-to-End-Funktionalität mithilfe eines Filtermechanismus löste, mit dem die Logik einer Methode durch Verschlüsse gefiltert werden kann. Um die Methode filterbar zu machen, erfordert die Implementierung von Li3 das manuelle Hinzufügen von Vorlagencode. Mit solchen Einschränkungen sind AOP-Techniken auf Filtertechniken beschränkt.
Andere bekannte AOP-Implementierungen in PHP:
Die PECL AOP-Erweiterung ist ein interessanter, aber gleichzeitig riskanter Ansatz, da die Unterstützung für PECL-Erweiterungen nicht üblich ist. Eine weitere Option sind Go! Libraries, eine AOP-Implementierung, die PHP-Code im laufenden Betrieb repariert und die Verwendung von AOP-Methoden ermöglicht.
Es gibt andere Implementierungen, aber die meisten basieren auf Proxys (soweit ich weiß), und dieser Ansatz weist viele Einschränkungen auf.
Neuer Typ in der Gegend
Die automatische Codegenerierung ist seit langem in PHP und wird in vielen Bibliotheken verwendet, beispielsweise in
ProxyManager. Und dank der Einführung von Composer,
Go! zeigt, dass das direkte Bearbeiten von Code möglich ist.
Wenn die Codegenerierung immer noch als einfach angesehen werden kann, ist die Korrektur des Codes etwas komplizierter. Erstens gibt es in PHP keinen integrierten Code-Parser, und zweitens gibt es nur sehr wenige Bibliotheken, die die Probleme beim Parsen von PHP-Code lösen. Die bekannteste ist die
PHP-Parser- Bibliothek. PHP-Parser ist ein großartiges Tool, aber selbst es ignoriert die Formatierung von Leerzeichen in generierten abstrakten Syntaxbäumen. Das macht es schwierig, den Code zu reparieren. In der Tat ist der Code, der repariert werden muss, echter ausführbarer Code. Wenn Sie möchten, dass das Backtracking fehlerfrei ist, müssen Sie daher die Zeilennummern in der korrigierten Datei berücksichtigen.
Für diese Aufgabe verwenden wir den Kahlan JIT Code
Patcher . Kahlan ist dank der JIT-Bearbeitungstechniken das neue Unit & BDD-Testframework, das Stub- und Monkey-Patchcode direkt in Ruby oder JavaScript ermöglicht. Unter der Haube finden wir, dass diese Bibliothek auf dem rudimentären PHP-Parser basiert. Trotzdem ist es schnell genug und stabil genug, um zu uns zu passen.
Die Filterbibliothek ist unter
github.com/crysalead/filter verfügbar und kann wie folgt verwendet werden.
Zunächst sollte der JIT-Code-Patcher so schnell wie möglich initialisiert werden (z. B. unmittelbar nach dem Einschalten des Autoloade Composer):
include __DIR__ . '/../vendor/autoload.php'; use Lead\Filter\Filters; Filters::patch(true);
Beachten Sie, dass die Codebearbeitung nur für Klassen möglich ist, die von Composer Autoload'er geladen wurden. Wenn eine Klasse mit den Ausdrücken require oder include hinzugefügt wird, wird sie bereits vor dem Aufruf von Filters :: patch (true) geladen und daher nicht behoben.
Standardmäßig wird der gesamte korrigierte Code unter / tmp / jit gespeichert. Sie können ihn jedoch jederzeit in Ihren eigenen Code ändern:
Filters::patch(true, ['cachePath' => 'my/cache/path/jit']);
Zwischengespeicherte Dateien werden bei jedem Ändern einer PHP-Datei automatisch wiederhergestellt.
Achtung!
Filters::patch(true)
ist der einfachste Weg, den Patcher zu konfigurieren. Beachten Sie, dass Ihr gesamter Code repariert wird. Es kann lange dauern, bis alle Methoden in Ihrer Codebasis in einen Filterabschluss eingeschlossen sind.
Glücklicherweise sind im Projekt nur einige Methoden erforderlich, wenn die End-to-End-Funktionalität bei gut gestaltetem Code eine entscheidende Rolle spielt. Daher besteht der bevorzugte Ansatz darin, nur die Methoden zu korrigieren, die gefiltert werden:
Filters::patch([ 'A\ClassName', 'An\Example\ClassName::foo', 'A\Second\Example\ClassName' => ['foo', 'bar'], ], [ 'cachePath' => 'my/cache/path/jit', ]);
Sie können also alle Methoden einer bestimmten Klasse festlegen, nur eine oder mehrere Methoden.
API-Filter
Nachdem der JIT-Patcher aktiviert ist, erstellen Sie einen Protokollfilter:
use Chaos\Filter\Filters; use Chaos\Database\Database; use Monolog\Logger; use Monolog\Handler\StreamHandler; $logger = new Logger('database'); $logger->pushHandler(new StreamHandler('my/log/path/db.log', Logger::WARNING)); Filters::apply(Database::class, 'query', function($next, $sql, $data, $options) use ($logger) { $logger->info('Ran SQL query: ' . $sql); return $next($sql, $data, $options); });
Im obigen Beispiel wird ein SQL-Abfrageprotokollfilter für die Chaos-Datenbankbibliothek erstellt. Weitere Informationen zum API-Filter finden Sie unter
github.com/crysalead/filter .
Fazit
AOP ist meiner Meinung nach die eigentliche Antwort auf die End-to-End-Funktionalität. Alle anderen Abstraktionen sind gleichermaßen redundant und in den meisten Fällen auf einen bestimmten Rahmen beschränkt. Ich verliere nicht die Hoffnung, dass PHP eines Tages eine integrierte API für die aspektorientierte Programmierung bereitstellen wird. Aber jetzt, denke ich, ist das Patchen von JIT-Code die beste Option, bei der die Vorteile den CPU-Overhead bei weitem überwiegen, was praktisch vernachlässigt werden kann, wenn das Patchen von JIT-Code nicht global angewendet wird.
DAS ENDE
Wie immer erwarten wir, wenn überhaupt, Fragen, einen Wunsch und laden Sie zu
einer offenen Lektion ein, in der Sie einen interessanten Vortrag anhören und den neuen
Lehrer besser kennenlernen können.