Schule der Magie PHP

Was ist Magie in PHP? Dies bedeutet normalerweise Methoden wie _construct() oder __get() . Die magischen Methoden in PHP sind Lücken, die Entwicklern helfen, erstaunliche Dinge zu tun. Das Netzwerk ist voll von Anweisungen zu deren Verwendung, mit denen Sie wahrscheinlich vertraut sind. Aber was ist, wenn wir sagen, dass Sie nicht einmal die wahre Magie gesehen haben? Denn je mehr du scheinst, alles zu wissen, desto mehr Magie entzieht sich dir.



Lassen Sie uns das etablierte Framework der OOP-Regeln fallen und das Unmögliche an der PHP School of Magic möglich machen. Der Haupt- und erste Zauberlehrer der Schule ist Alexander Lisachenko ( NightTiger ). Er wird das magische Denken unterrichten und vielleicht werden Sie magische Methoden, nicht standardisierte Methoden zum Zugreifen auf Eigenschaften, Ändern von Kontexten, aspektorientiertes Programmieren und Stream-Filter lieben.


Alexander Lisachenko ist der Leiter der Abteilung für Webentwicklung und Architektur in Alpari. Der Autor und Hauptentwickler des aspektorientierten Frameworks Go! Aop . Referent bei internationalen Konferenzen zu PHP.

In dem guten Film "Die Illusion der Täuschung" gibt es einen Satz:
"Je näher du bist, desto weniger siehst du."

Dasselbe gilt für PHP als Zaubertrick, mit dem Sie ungewöhnliche Dinge tun können. Aber zuallererst wurde es geschaffen, um Sie zu täuschen: "... eine Handlung, die dazu gedacht ist, entweder jemanden zu betrügen, oder als Witz oder Form der Unterhaltung."

Wenn wir PHP zusammen nehmen und versuchen, etwas Magisches darauf zu schreiben, werde ich Sie höchstwahrscheinlich täuschen. Ich werde einen Trick machen, und Sie werden sich lange fragen, warum dies passiert. Das liegt daran, dass PHP eine Programmiersprache ist, die für ihre ungewöhnlichen Dinge bekannt ist.

Magische Ausrüstung


Was brauchen wir von magischer Ausrüstung? Schmerzlich vertraute Methoden.

__construct(), __destruct(), __clone(),
__call(), __callStatic(),
__get(), __set(), __isset(), __unset(),
__sleep(), __wakeup(),
__toString(), __invoke(), __set_state(),
__debugInfo()


Ich werde die letzte Methode separat erwähnen - damit können Sie ungewöhnliche Dinge aufdrehen. Das ist aber noch nicht alles.

  • declare(ticks=1) .
  • debug_backtrace() . Dies ist unser Begleiter, um zu verstehen, wo wir uns im aktuellen Code befinden, wer uns angerufen hat und warum, mit welchen Argumenten. Nützlich, um zu entscheiden, nicht der ganzen Logik zu folgen.
  • unset(), isset() . Es scheint nichts Besonderes zu sein, aber diese Designs verbergen eine Menge Tricks, die wir weiter betrachten werden.
  • by-reference passing . Wenn wir ein Objekt oder eine Variable als Referenz übergeben, sollten wir damit rechnen, dass Ihnen unweigerlich etwas Magie zustoßen wird.
  • bound closures . Auf den Verschlüssen und der Tatsache, dass sie binden können, können Sie viele Tricks bauen.
  • Mit der Reflection-API können Sie die Reflektion auf eine neue Ebene heben.
  • StreamWrapper-API.

Die Ausrüstung ist fertig - ich werde die erste Regel der Magie erinnern.

Sei immer der klügste Kerl im Raum.

Trick Nr. 1. Unmöglicher Vergleich


Beginnen wir mit dem ersten Trick, den ich Impossible Comparison nenne.
Schauen Sie sich den Code genau an und prüfen Sie, ob dies in PHP möglich ist.



Es gibt eine Variable, wir deklarieren ihren Wert und dann ist sie plötzlich nicht mehr gleich sich selbst.

Nicht eine Nummer


Es gibt solch ein magisches Artefakt wie NaN - Not-a-Number.



Das Erstaunliche ist, dass es sich selbst nicht ebenbürtig ist. Und dies ist unser erster Trick: Verwende NaN, um einen Freund zu rätseln. NaN ist jedoch nicht die einzige Lösung für diese Aufgabe.

Wir verwenden Konstanten




Der Trick ist, dass wir false für namespace und compare als true deklarieren können. Der unglückliche Entwickler wird sich lange fragen, warum es true und nicht false .

Handler


Der nächste Trick ist eine stärkere Artillerie als die beiden vorherigen. Mal sehen, wie es funktioniert.



Der Trick basiert auf tick_function und tick_function , wie tick_function declare(ticks=1) tick_function declare(ticks=1) .

Wie funktioniert das alles? Zuerst deklarieren wir eine Funktion, und als Referenz wird der isMagic Parameter verwendet. Anschließend wird versucht, diesen Wert in true zu ändern. Nachdem wir declare(ticks=1) deklariert haben declare(ticks=1) ruft der PHP-Interpreter nach jeder elementaren Operation register_tick_function - callback auf. In diesem Rückruf können wir den Wert, der zuvor false in true ändern. Die Magie!

Trick Nr. 2. Magische Ausdrücke


Nehmen Sie ein Beispiel, in dem zwei Variablen deklariert sind. Einer von ihnen ist false , der andere ist true . Wir isBlack und isWhite und var_dump das Ergebnis. Was denkst du wird das Ergebnis sein?



Vorrangige Bediener . Die richtige Antwort ist false , weil es in PHP so etwas wie „Operator-Priorität“ gibt.



Überraschenderweise hat der logische Operator or die Zuweisung weniger Priorität als die Operation. Daher wird einfach false zugewiesen. In isWhite kann es einen beliebigen anderen Ausdruck geben, der ausgeführt wird, wenn der erste Teil fehlschlägt.

Magische Ausdrücke


Schauen Sie sich den folgenden Code an. Es gibt eine Klasse, die den Konstruktor enthält, und eine Factory, deren Code weiter unten angegeben wird.



Achten Sie auf die letzte Zeile.

 $value = new $factory->build(Foo::class); 

Es gibt verschiedene Möglichkeiten, die auftreten können.

  • $factory wird als Klassenname new ;
  • es wird ein Parsing-Fehler auftreten;
  • es wird der Aufruf $factory->build() verwendet, dessen Wert diese Funktion $factory->build() , das Ergebnis ist new ;
  • Der Wert der Eigenschaft $factory->build wird zum $factory->build der Klasse verwendet.

Schauen wir uns die letzte Idee an. In der Klasse $factory deklarieren wir eine Reihe magischer Funktionen. Sie schreiben, was wir tun: Rufen Sie die Eigenschaft auf, rufen Sie die Methode auf oder versuchen Sie sogar, invoke für das Objekt invoke .

 class Factory { public function _get($name) {echo "Getting property {$name}"; return Foo::class;} public function _call($name, $arg) {echo "Calling method {$name}"; return Foo::class;} public function _invoke($name) {echo "Invoking {$name}"; return Foo::class;} } 

Die richtige Antwort: Wir rufen keine Methode auf, sondern eine Eigenschaft. Nach $factory->build gibt es einen Parameter für den Konstruktor, den wir an diese Klasse übergeben.

Übrigens habe ich in diesem Framework eine Funktion namens "Abfangen der Erstellung neuer Objekte" implementiert - Sie können dieses Design "sperren".

Parser-Lücke


Das folgende Beispiel ist für den PHP-Parser selbst. Haben Sie jemals versucht, Funktionen aufzurufen oder Variablen in geschweiften Klammern zuzuweisen?



Ich habe diesen Trick auf Twitter, es funktioniert extrem nicht-Standard.

 $result = ${'_' . !$_=getCallback()}(); $_=getCallback(); // string(5) "hello" !$_=getCallback()}(); // bool(false) '_'.!$_=getCallback()}(); // string(1) "_" ${'_'.!$_=getCallback()}(); // string(5) "hello" 

Zunächst weisen wir der Variablen _ (Unterstrich) den Wert des Ausdrucks zu. Wir haben bereits eine Variable, wir versuchen, ihren Wert logisch zu invertieren, und wir bekommen false - die Zeile wird wie auf true . Dann kleben wir alles im Variablennamen zusammen, durch den wir uns dann in die geschweiften Klammern drehen.

Was ist Magie? Dies ist Unterhaltung, die es uns ermöglicht, uns inspiriert und ungewöhnlich zu fühlen und zu sagen: „Was? Also war es möglich?! "

Trick Nr. 3. Regeln brechen


Was ich an PHP mag, ist, dass Sie die Regeln brechen können, die jeder erstellt, um supersicher zu sein. Es gibt ein Design namens "Sealed Class", das einen privaten Konstruktor hat. Ihre Aufgabe als Schüler des Magiers ist es, eine Instanz dieser Klasse zu erstellen.



Betrachten Sie dazu drei Möglichkeiten.

Umgehung


Der erste Weg ist der offensichtlichste. Es sollte jedem Entwickler bekannt sein - dies ist die Standard-API, die uns die Sprache bietet.



Mit newInstanceWithoutConstructor Konstrukt newInstanceWithoutConstructor können Sie die Spracheinschränkungen umgehen, die für den Konstruktor gelten, und eine Instanz der Klasse erstellen, die alle unsere privaten Konstruktordeklarationen umgeht.

Die Option funktioniert, ist einfach, bedarf keiner Erklärung.

Kurzschluss


Die zweite Option erfordert mehr Aufmerksamkeit und Geschicklichkeit. Es wird eine anonyme Funktion erstellt, die dann an den Fischadler dieser Klasse gebunden wird.



Hier sind wir in der Klasse und können sicher private Methoden aufrufen. Wir verwenden dies, indem wir new static aus dem Kontext unserer Klasse aufrufen.



Deserialisierung


Die dritte Option ist meiner Meinung nach die am weitesten fortgeschrittene.



Wenn Sie eine bestimmte Zeile in einem bestimmten Format schreiben, ersetzen Sie dort bestimmte Werte - unsere Klasse wird sich herausstellen.



Nach der Deserialisierung erhalten wir unsere instance .

Doktrin / Instantiator-Paket


Magie wird oft zu einem dokumentierten Framework oder einer Bibliothek - zum Beispiel in Doctrine / Instantiator wird all dies implementiert. Wir können beliebige Objekte mit beliebigem Code erstellen.

 composer show doctrine/instantiator --all name : doctrine/instantiator descrip. : A small, lightweight utility to instantiate objects in PHP without invoking their constructors keywords : constructor, instantiate type : library license : MIT License (MIT) 

Trick Nr. 4. Abfangen des Zugangs zu Eigentum


Die Wolken ziehen auf: Die Klasse ist geheim, die Eigenschaften und der Konstruktor sind privat und auch der Rückruf.

 class Secret { private $secret = 42; private function _construct() { echo 'Secret is: ', $this->secret; } private function onPropAccess(string $name) { echo "Accessing property {$name}"; return 100500; } } // How to create a secret instance and intercept the secret value? 

Unsere Aufgabe als Assistenten ist es, einen Rückruf zu tätigen.

Hinzufügen der Magie ... Getter


Fügen Sie eine Prise Magie hinzu, damit es funktioniert.



Diese Prise Magie ist ein magischer getter . Es ruft eine Funktion auf, und bisher ist nichts Schlimmes passiert. Wir werden jedoch den vorherigen Trick anwenden und eine Instanz dieses Objekts erstellen, die das private Konstrukt umgeht.



Jetzt müssen wir den Rückruf irgendwie anrufen.

"Unset" im Schaltkreis


Erstellen Sie dazu einen Abschluss. Innerhalb des Abschlusses, der sich im Gültigkeitsbereich der Klasse befindet, löschen wir diese Variable mit der Funktion unset() .



unset können Sie eine Variable vorübergehend ausschließen, wodurch unsere magic get Methode aufgerufen werden kann.

Wir rufen den privaten Konstrukteur an


Da wir einen privaten Konstruktor haben, der echo anzeigt, können Sie diesen Konstruktor einfach abrufen und durch Aufrufen zugänglich machen.



Also zerfiel unsere Geheimklasse.



Wir haben eine Nachricht erhalten, dass wir:

  • abgefangen;
  • etwas ganz anderes zurückgegeben.

Leedavis / Altr-Ego-Paket


Viel Magie ist bereits dokumentiert. Das altr-ego- Paket gibt nur vor, Ihre Komponente zu sein.

 composer show leedavis81/altr-ego --all name : leedavis81/altr-ego descrip. : Access an objects protected / private properties and methods keywords : php, break scope versions : dev-master, v1.0.2, v1.0.1, v1.0.0 type : library license : MIT License (MIT) 

Sie können eines Ihrer Objekte erstellen und ein zweites daran anhängen. Dadurch können Änderungen an der Einrichtung vorgenommen werden. Er wird sich gehorsam verändern und alle Ihre Wünsche erfüllen.

Trick Nr. 5. Unveränderliche Objekte in PHP


Gibt es unveränderliche Objekte in PHP? Ja und eine sehr, sehr lange Zeit.

 namespace Magic { $object = (object) [ "\0Secret\0property" => 'test' ]; var_dump($object); } 

Erhalten Sie sie einfach auf interessante Weise. Das Interessante ist, dass wir ein Array mit einem speziellen Schlüssel erstellen. Es beginnt mit der Konstruktion \0 - dies ist ein Null-Byte-Zeichen, und nach Secret wir auch \0 .

Das Konstrukt wird in PHP verwendet, um eine private Eigenschaft innerhalb einer Klasse zu deklarieren. Wenn wir versuchen, ein Objekt in ein Array umzuwandeln, sehen wir dieselben Schlüssel. Wir werden nichts als stdClass . Es enthält eine Privateigenschaft aus der Klasse Secret , die test .

 object(stdClass) [1] private 'property' (Secret) => string 'test' (length=4) 

Das einzige Problem ist, dass Sie diese Eigenschaft von dort aus nicht erhalten können. Es ist erstellt, aber nicht verfügbar.

Ich fand es ziemlich unpraktisch - wir haben unveränderliche Objekte, aber Sie können es nicht verwenden. Daher entschied ich mich, dass es Zeit war, meine Entscheidung einzureichen. Ich habe mein gesamtes Wissen und meine Magie, die in PHP verfügbar sind, genutzt, um eine Konstruktion zu erstellen, die auf all unseren Zaubertricks basiert.

Beginnen wir mit einem einfachen: Erstellen Sie ein DTO und versuchen Sie, alle darin enthaltenen Eigenschaften abzufangen (siehe den vorherigen Trick).

Wir speichern an einem sicheren Ort die Werte , die wir von dort erfassen. Sie werden mit keiner Methode zugänglich sein: weder reflection , noch Verschlüsse, noch andere Magie. Aber es besteht Unsicherheit - gibt es einen solchen Platz in PHP, der garantiert, dass einige Variablen gespeichert werden, damit kein schlauer junger Programmierer dorthin gelangt?

Wir bieten eine magische Methode , mit der Sie diesen Wert ablesen können. Zu diesem isset verfügen wir über Magic getters , Magic isset Methoden, mit denen wir APIs bereitstellen können.

Kehren wir zu einem verlässlichen Ort zurück und versuchen zu suchen.

  • Global variables gelöscht - jeder kann sie ändern.
  • Public properties ebenfalls nicht geeignet.
  • Protected properties so lala, weil die untergeordnete Klasse durchkommt.
  • Private properties . Es gibt kein Vertrauen, weil es durch Schließen oder durch reflection verändert werden kann.
  • Private static properties können ausprobiert werden, aber auch die reflection unterbrochen.

Es scheint, dass es keinen Ort gibt, an dem man die Werte von Variablen verbergen kann. Aber es gab eine magische Sache - Static variables in functions - das sind Variablen, die sich in Funktionen befinden.

Sichere Aufbewahrung von Werten


Ich habe Nikita Popov und Jay Watkins auf dem speziellen Stack Overflow-Kanal danach gefragt.



Dies ist eine Funktion, in der eine statische Variable deklariert wird. Kann man das irgendwie ändern? Die Antwort lautet nein.

Wir haben eine kleine Lücke in der Welt der geschützten Variablen gefunden und wollen sie nutzen.

Werte per Link übergeben


Wir werden es nicht standardmäßig als Eigentum des Objekts verwenden. Da Sie jedoch keine Eigenschaft übergeben können, verwenden wir die klassische Übertragung von Werten als Referenz.



Es stellt sich heraus, dass es eine Klasse gibt, in der es eine magische callStatic Methode gibt, in der die Static Variable deklariert ist. Bei jedem Aufruf einer Funktion übergeben wir den Wert der Variablen aus dem Immutable-Objekt unter Bezugnahme auf alle unsere verschachtelten Methoden. Wir stellen also irgendwie den Kontext zur Verfügung.

Zustand speichern


Mal sehen, wie der Zustand gerettet wird.



Es ist ziemlich einfach. Für das übertragene Objekt verwenden wir die Funktion spl_object_id , die für jede Instanz einen eigenen Bezeichner zurückgibt. Der State , den wir bereits von dem Objekt erhalten haben, versucht dort zu retten. Nichts Besonderes.

Wenden Sie den Status des Objekts an


Auch hier gibt es eine Konstruktion zum Übergeben von Werten anhand von Referenzen und nicht unset Eigenschaften. Wir deaktivieren alle aktuellen Eigenschaften, nachdem wir sie zuvor in der Statusvariablen gespeichert haben, und legen diesen Kontext für das Objekt fest. Das Objekt enthält keine Eigenschaften mehr, sondern nur seinen Bezeichner, der mit spl_object_id deklariert und an dieses Objekt angehängt wird, solange es noch aktiv ist.



Status abrufen


Dann ist alles einfach.



Wir bekommen diesen Zusammenhang auf den Magic getter und nennen unser Eigentum daraus. Jetzt kann niemand und nichts den Wert ändern, nachdem dieses Trait verbunden wurde.



Alle magischen Methoden werden überschrieben und implementieren die Unveränderlichkeit des Objekts.



Lisachenko / unveränderliches Objekt


Wie erwartet ist alles sofort in der Bibliothek formalisiert und einsatzbereit.

 composer show /immutable-object --all name : /immutable-object descrip. : Immutable object library keywords : versions : * dev-master type : library license : MIT License (MIT) 

Die Bibliothek sieht ziemlich einfach aus. Wir verbinden es und schaffen unsere Klasse. Es hat verschiedene Eigenschaften: privat, geschützt und öffentlich. Wir verbinden ImmutableTrait .



Danach können Sie das Objekt einmalig initiieren - siehe Wert. Es ist dort wirklich gespeichert und sieht sogar aus wie ein echter DTO.

 object (MagicObject) [3] public 'value' => int 200 

Aber wenn wir versuchen, es zu ändern, zum Beispiel so ...



... dann bekomme sofort eine fatal exception . Wir können eine Eigenschaft nicht ändern, da sie unveränderlich ist. Wie so



Wenn Sie sich auf eine aufregende Herausforderung einlassen und versuchen, sie zu entwerten, erhalten Sie Folgendes.



Das ist mein Geschenk. Sobald Sie versuchen, in PHPStorm innerhalb dieser Klasse einen Fehler zu machen, wird die Ausführung Ihres Befehls sofort gestoppt. Ich möchte nicht, dass Sie sich mit diesem Code befassen - er ist zu gefährlich. Er wird warnen, dass es nichts zu tun gibt.

Trick Nr. 6. Thread-Verarbeitung


Betrachten Sie das Design.

 include 'php://filter/read=string.toupper/resource=magic.php'; 

Es gibt etwas Magisches: Ein PHP-Filter, read , am Ende ist eine Art magic.php- Datei angeschlossen . Diese Datei sieht ziemlich einfach aus.

 <?php echo 'Hello, world!' 

Beachten Sie, dass der Fall anders ist. Wenn wir die Datei jedoch über unser Design „füllen“, erhalten wir Folgendes:

 HELLO, WORLD! 

Was ist in diesem Moment passiert? Durch die Verwendung der Konstruktion des PHP-Filters in include können Sie jeden Filter, einschließlich Ihres Filters, anschließen, um den Quellcode zu analysieren. Sie verwalten alles in diesem Quellcode. Sie können final aus Klassen und Methoden entfernen, Eigenschaften öffentlich machen - alles, was Sie durch dieses Ding drehen können.

Ein Teil meines Aspekt-Frameworks basiert darauf. Wenn Ihre Klasse verbunden ist, analysiert sie sie und wandelt sie in das um, was ausgeführt wird.

In PHP gibt es bereits eine ganze Reihe von vorgefertigten Filtern.

 var_dump(stream_get_filters()); array (size=10) 0 => string 'zlib.*' (length=6) 1 => string 'bzip2.*' (length=7) 2 => string 'convert.iconv.*' (length=15) 3 => string ' string.rotl3' (length=12) 4 => string 'string.toupper' (length=14) 5 => string 'string.tolower' (length=14) 6 => string 'string.strip_tags' (length=17) 7 => string 'convert.*' (length=9) 8 => string 'consumed' (length=8) 9 => string 'dechunk' (length=7) 

Sie können den Inhalt "zip", in Groß- oder Kleinschreibung übersetzen.

Die wichtigsten Tricks, die ich zeigen wollte, sind vorbei. Kommen wir nun zur Quintessenz von allem, was ich tun kann - aspektorientierte Programmierung.

Trick Nr. 7. Aspektorientierte Programmierung


Schauen Sie sich diesen Code an und überlegen Sie, ob er aus Ihrer Sicht gut oder schlecht ist.



Der Code scheint völlig ausreichend zu sein. Es überprüft die Zugriffsrechte, führt die Protokollierung durch, erstellt einen Benutzer, bleibt bestehen und versucht, eine exception abzufangen.

Wenn Sie sich all diese Nudeln ansehen, wird dies bei jeder unserer Methoden wiederholt, und das einzig Wertvolle dabei ist, dass sie grün markiert sind.



Alles andere: "Nebenbedenken" oder "Querschnittsbedenken" sind Querschnittsfunktionen.

Herkömmliches OOP macht es unmöglich, alle diese Strukturen mit Copy-Paste zu kopieren, zu entfernen und irgendwo herauszunehmen. Das ist schlecht, weil man es wiederholen muss. Ich wünschte, der Code sah immer sauber und ordentlich aus.



Damit es keine Protokollierung enthält (lass es irgendwie angewendet werden) und keine security enthält.



Das ist also alles, einschließlich Protokollierung ...



... und eine Sicherheitskontrolle, ...



... von selbst durchgeführt.

Und es ist möglich.

Glossar "Aspekt"


Es gibt eine Sache namens Aspekt. Dies ist ein einfaches Beispiel, das Berechtigungen überprüft. Dank ihm können Sie einige Anmerkungen sehen, die auch durch das Plugin für PhpStorm hervorgehoben werden. "Aspect" deklariert SQL-Ausdrücke, auf welche Punkte im Code diese Bedingung angewendet werden soll. Im Folgenden möchten wir beispielsweise einen Abschluss auf alle öffentlichen Methoden der UserService Klasse UserService .



Wir erhalten den Abschluss mit der Methode $invocation .



Dies ist eine Art Wrapper über der reflection , die weitere Argumente enthält.

Weiter können Sie in diesem Callback für jede Methode die notwendigen Zugriffsrechte überprüfen, dies wird als "Advice" bezeichnet.



Wir sagen sozusagen die Sprache: "Lieber PHP, bitte wenden Sie diese Methode vor jedem Aufruf der öffentlichen Methode der UserService Klasse an UserService " Nur eine Zeile, aber sehr nützlich.

Aspekt vs Ereignis-Listener


Um es klarer zu machen, habe ich Aspect mit Event Listener verglichen. Viele arbeiten bei Symfony und wissen, was Event Dispatcher ist.



Sie ähneln sich darin, dass wir eine Art Abhängigkeit übergeben, z. B. AutorizationChecker , und AutorizationChecker , wo in diesem Fall die Anwendung erfolgen soll. Im Fall von Listener ist dies ein SubscrabingEvent Namen UserCreate . Im Fall von Aspect abonnieren wir alle Aufrufe öffentlicher Methoden vom UserService . callback : - .

, .

, , Aspects .



. , PHP- .



, . , , OPcache.

. Composer . Go! AOP, Composer , .



Aspects , Aspects . .

.

PHP-Parser . , , . , , PHP-Parser . .



. , goaop/parser-reflection .



AST- , . , , , .

.



, , Aspect .



, .



, , . — , - , .



, . , .

Aspect MOCK. «», , . .

joinPoint . - joinPoint : , , .

Was weiter?


.

OPcache preloading for AOP Core . AOP- . 10 . Bootstrapping , PHP.

FFI integration to modify binary opcodes . , , . PHP-opcodes, .bin . FFI .

Modifying PHP engine internal callbacks PHP- userland. PHP . FFI PHP userland, , , . .

, .

#8. goaop/framework


, GitHub .

 composer show goaop/framework --all name : goaop/framework descrip. : Framework for aspect-oriented programming in PHP. keywords : php, aop, library, aspect versions : dev-master, 3.0.x-dev, 2.x-dev, 2.3.1, … type : library license : MIT License 

, PhpStorm.



, Pointcuts. , , . — , , .

Trick #9.


. , .

: , - . fastcgi_finish_request . , , , - callback — .

?

, Deffered , , .



Aspect , , , Deffered , .



Aspect : , , , callback, , callback. .

React , promise . , - , - , .

, .



shutdown_function Aspect . , callback, , , , callback onPhpTerminate . fastcgi_finish_request : «, , , , ». .

, sendPushNotification .



, - — 2 .



, , , 2 .

, Deferred .



, . - , , .

Das ist alles. , - . , .

PHP Russia 2020 . — . telegram- , PHP Russia 2020.

Source: https://habr.com/ru/post/de478618/


All Articles