Neu in Runkit 1.0.4: PHP 5.6+, Schließungen überall und 12 weitere neue Funktionen

    Runkit 1.0.4 für PHP veröffentlicht!


    Herzlichen Glückwunsch an alle Runkit-Benutzer zum lang erwarteten Mega-Release! Wenn Sie Runkit ständig verwenden und mit dessen Funktionen, Verlauf und Entwicklung vertraut sind, können Sie sofort mit der Beschreibung der Änderungen in Release 1.0.4 fortfahren . In jedem Fall schlage ich vor, den gesamten Artikel zu lesen.



    Was ist Runkit?


    Runkit ist eine Erweiterung der PHP-Sprache, mit der Sie Dinge tun können, die aus der Sicht dieser Sprache unmöglich sind. Die Erweiterungsfunktion besteht aus drei Teilen.

    Laufzeitmanipulationen


    Mit dem ersten und größten Teil der Runkit-Funktionalität können Sie dynamisch (während der Ausführung eines PHP-Programms) Entitäten kopieren, ändern und löschen, deren dynamische Änderung nicht von der PHP-Sprache selbst bereitgestellt wird.

    Mit Runkit können Sie vorhandene Funktionen (einschließlich der in die Sprache eingebauten) kopieren, neu definieren und löschen, eine Klasse dynamisch zu einem Nachkommen einer anderen Klasse machen, den gesamten Inhalt erben (runkit_class_adopt) oder die Klasse vom übergeordneten Element trennen, indem Sie den geerbten Inhalt löschen (runkit_class_emancipate). Sie können auch Methoden vorhandener Klassen hinzufügen, kopieren, überschreiben und löschen sowie deren Eigenschaften hinzufügen und entfernen. Außerdem können Sie mit Runkit zuvor definierte Konstanten überschreiben und löschen.

    Runkit_sandbox


    Der zweitgrößte Teil der Funktionalität sind die Runkit_Sandbox-Sandboxen. Mit ihnen können Sie einen Teil des Programms in PHP in einer isolierten Umgebung ausführen. Jede Sandbox kann ihre eigenen PHP-Sicherheitseinstellungen haben, wie safe_mode, safe_mode_gid, safe_mode_include_dir, open_basedir, allow_url_fopen, disable_functions, disable_classes. Darüber hinaus kann jede Sandbox ihre eigene Runkit-Funktionalität auf ihre eigene Weise konfigurieren: Sie können ihre eigenen superglobalen Variablen (wir werden sie weiter unten erörtern) ablegen und das Ändern integrierter Funktionen verhindern.

    Sandboxes können PHP-Dateien einschließen (über include (), include_once (), require () und require_once ()), Funktionen in sich selbst aufrufen, beliebigen PHP-Code ausführen, die Werte ihrer internen Variablen drucken und ihre Arbeit abschließen. Darüber hinaus können Sie eine Funktion zum Abfangen und Verarbeiten der Ausgabe der Sandbox angeben.

    Innerhalb der Sandbox können Sie auch ein Anti-Sandbox-Objekt Runkit_Sandbox_Parent erstellen, um die Sandbox der übergeordneten Umgebung zuzuordnen. Die Funktionalität der "Anti-Sandboxes" ist der Funktionalität der "Sandboxes" sehr ähnlich, jedoch sollte aus Sicherheitsgründen jede Funktion, die eine Verbindung mit der externen Umgebung herstellt, beim Erstellen der "Sandbox" explizit aktiviert werden.

    Superglobals


    Mit Runkit können Sie auch neue superglobale Variablen zu PHP hinzufügen. Um solche Variablen hinzuzufügen, genügt es, ihre Namen mit einem Komma in der Eigenschaft runkit.superglobal in der PHP-Konfigurationsdatei aufzulisten.

    Andere


    Zusätzlich zu den drei Hauptteilen der Funktionalität bietet Runkit Tools zum Überprüfen der Syntax von PHP-Code (runkit_lint und runkit_lint_file) sowie eine Funktion runkit_import, mit der Sie eine PHP-Datei wie include importieren können, den gesamten globalen Code in dieser Datei jedoch ignorieren können. Abhängig von den Flags kann runkit_import Funktionen oder Klassen (ganz oder teilweise) importieren, vorhandene überschreiben oder beibehalten.

    Warum wird Runkit benötigt?


    Runkit hilft PHP-Programmierern, viele verschiedene Probleme zu lösen. Ich werde über ein paar grundlegende Dinge sprechen.

    Programme anderer Leute patchen


    Stellen Sie sich vor, Sie verwenden eine Bibliothek (oder ein Framework) eines Drittanbieters und müssen irgendwann das Verhalten ändern. Der Code, der geändert werden muss, befindet sich jedoch in der privaten Methode einer der Bibliotheksklassen. Die naheliegende Lösung besteht darin, die Datei zu bearbeiten, die diese Methode enthält. Dies ist eine funktionierende Lösung, jedoch wurde der Bibliothekscode jetzt geändert und die Aktualisierung wird zu einer mühsamen Aufgabe, da Sie den Patch jedes Mal anwenden müssen, wenn Sie die Bibliothek aktualisieren. Eine andere Lösung besteht darin, Runkit zu verwenden, um die für uns interessante Methode zu überschreiben. Dies geschieht mit einem einzigen Aufruf der Funktion runkit_method_redefine. Es gibt eine ähnliche Lösung für die Neudefinition der Funktionen (runkit_function_redefine) und Konstanten (runkit_constant_redefine), die bereits im Programm vorhanden sind. Eine ähnliche Änderung des Programmcodes zur Laufzeit wird als "Affen-Patching" bezeichnet. In speziellen Online-Foren finden Sie verschiedene Rezepte zum Patchen mit Hilfe von Runkit-Bibliotheken wie WordPress, 1C-Bitrix, CodeIngniter, Laravel usw. Um einige Probleme zu lösen, kann es nützlich sein, Funktionen zu ersetzen, die in die PHP-Sprache selbst integriert sind, und Runkit kann dies auch tun.

    Isolierte Umgebung zum Ausführen von benutzerdefinierten Skripten


    Mithilfe von Sandboxes erstellt Runkit_Sandbox häufig Umgebungen für die Ausführung von benutzerdefiniertem Code. Bei richtiger Konfiguration ist es dadurch möglich, Benutzercode vom Hauptsystem zu isolieren. In seiner einfachsten Form sieht es so aus:

    $options = […];
    $sandbox = new Runkit_Sandbox($options);
    $sandbox->ini_set(…);
    $sandbox->eval($code);
    

    Andere Anwendungsfälle


    Mit runkit können Sie auch Programmcode-Updates im laufenden Betrieb organisieren, wie dies zum Beispiel in phpdaemon der Fall ist (siehe habrahabr.ru/post/104811 ).

    Unit-Tests


    Die Fähigkeit von Runkit, Funktionen und Methoden zu überschreiben, macht es äußerst nützlich, wenn Unit-Tests in PHP geschrieben werden. Mit Runkit wird das Erstellen von Test-Doubles (Stubs oder "Spies") während der Testausführung einfach, auch wenn die Architektur des getesteten Codes keine Abhängigkeitsinjektion unterstützt . Es gibt fertige Bibliotheken, die die Substitution von PHP-Methoden und -Funktionen für Stubs im Rahmen von Unit-Tests implementieren (z. B. ytest , phpspy und andere). Mit der richtigen Bibliothek können Sie erstaunlich einfache Tests erhalten (siehe zum Beispiel hier ).

    Geschichte von Runkit


    Starten Sie


    Runkit wurde 2005 von Sara Golemon (gegründet Sara Golemon ). Die neueste Veröffentlichung des Autors (Version 0.9) wurde am 06.06.06 veröffentlicht. Im Oktober 2006 hat Sarah die Unterstützung der Erweiterung eingestellt, ohne Version 1.0 zu veröffentlichen. Zu dieser Zeit enthielt Runkit Funktionen zum Bearbeiten von Konstanten, Funktionen, Methoden, runkit_import, eine Funktion zum Hinzufügen von Eigenschaften zu Klassen, Syntaxprüfungsfunktionen, Sandboxes und superglobalen Variablen. Die Dokumentation auf der php.net-Website ( http://php.net/runkit ) ist um die Version 0.7 eingefroren , sodass sie noch nicht einmal einen Teil der von Sarah selbst erstellten Funktionen beschreibt. Darüber hinaus wird in dieser Dokumentation die gesamte Funktionalität von Runkit als experimentell bezeichnet, was 2006 relevant war, jetzt aber absolut unwahr ist.

    Ablehnen


    Von Oktober 2006 bis Oktober 2009 wurde die Erweiterung von niemandem unterstützt, und die PHP-Sprache wurde weiterentwickelt. Trotz der Änderungen durch Mitglieder der PHP-Community war Runkit in PHP 5.2 bereits instabil und verursachte Segmentierungsfehler.

    Wiedergeburt


    Im Oktober 2009 begann ich, Runkit zu reparieren und entwickelte es dann unter https://github.com/zenovich/runkit . Ich sage Ihnen, welche Releases in dieser Zeit veröffentlicht wurden und welche Änderungen darin enthalten sind.

    Release 1.0.0 (1. April 2010)


    Tatsächlich ist diese Veröffentlichung nie passiert, sie ist fiktiv :). Es enthält alle Community-Änderungen nach der Veröffentlichung von Version 0.9 und vor der Veröffentlichung von 1.0.1.

    Release 1.0.1 (3. Oktober 2010)


    Die erste echte Veröffentlichung von Runkit nach 2006. Jetzt unterstützt Runkit alle Versionen von PHP bis einschließlich 5.3. Mehr als zehn schwerwiegende Fehler wurden behoben, einschließlich derer, die zu PHP-Abstürzen führten. Die wichtigsten sind:
    • Abstürze beim Import durch runkit_import () von Eigenschaften und Konstanten mit Array-Werten behoben,
    • Abstürze beim Import von Funktionen und Methoden mit statischen Variablen behoben,
    • Absturz bei der Manipulation von Funktionen behoben,
    • Absturz von runkit_method_copy beim Arbeiten mit geschützten Methoden behoben,
    • Absturz beim Herunterfahren von PHP nach Änderung der eingebauten Funktionen behoben,
    • Absturz beim Aufruf der ursprünglichen Methode nach Anwendung der Funktion runkit_method_copy behoben, wenn die Methode statische Variablen hatte
    • Die Namen der generierten Methoden werden nicht mehr in Kleinbuchstaben geschrieben.

    Das Release 1.0.1 bietet die Möglichkeit, statische Methoden mit der neuen Konstante RUNKIT_ACC_STATIC zu definieren und zu ändern:

    runkit_method_add('MyClass', 'newMethod', '$arg1, $arg2', '/* some code here*/', RUNKIT_ACC_STATIC);
    

    Es wurde auch die Möglichkeit hinzugefügt, statische Klasseneigenschaften zu importieren. Beim Importieren einer Klasse werden statische Eigenschaften standardmäßig kopiert, ihr Import kann jedoch mithilfe der neuen Konstante RUNKIT_IMPORT_CLASS_STATIC_PROPS deaktiviert werden:

    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASSES); // импортировать классы целиком
    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASSES & ~ RUNKIT_IMPORT_CLASS_STATIC_PROPS); // импортировать классы, но не импортировать их статические свойства
    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASS_STATIC_PROPS); // импортировать только статические свойства классов
    

    Darüber hinaus wurde in der Version die Möglichkeit hinzugefügt, mithilfe von Runkit_Sandbox :: call_user_func () einen Abschluss auf eine Sandbox anzuwenden.

    Release 1.0.2 (5. Oktober 2010)


    Bugfix der Vorgängerversion. Verbesserte Kompatibilität mit PHP 5.3.

    Release 1.0.3 (2. Januar 2012)


    Vererbung beim Umbenennen von Methoden mit runkit_method_rename behoben. Die Assembly der Erweiterung für Windows wurde behoben.

    Release 1.0.4 (25. September 2015)


    Das lang erwartete Mega Release! Volle Unterstützung für PHP5 (bis einschließlich PHP 5.6).

    In dieser Version wurde viel getan, um die Arbeit von Runkit zu stabilisieren: Für jede PHP-Version wurden Tests in vier Versionen durchgeführt: mit und ohne ZTS, mit und ohne valgrind. Für fast jede Änderung wurden neue Tests hinzugefügt. Dadurch konnten eine Vielzahl von Fehlern erkannt und behoben werden.

    Zu den wichtigen Korrekturen gehören:
    • Abstürze beim Ändern, Löschen oder Umbenennen von Funktionen, Methoden und Eigenschaften von Klassen, für die zuvor Reflection-Objekte erstellt wurden, wurden behoben.
    • Absturz beim Erstellen von Runkit_Sandbox mit aktivierter Einstellung register_globals behoben
    • Absturz aufgrund eines Syntaxfehlers in einer über runkit_import () geladenen Datei behoben,
    • Absturz beim Arbeiten mit Konstanten mit Namen eines Zeichens behoben,
    • Absturz beim Aufrufen einer umbenannten privaten oder geschützten Methode behoben.

    Insgesamt wurden im Release mehr als vierzig (!!!) wichtige Korrekturen vorgenommen, deren vollständige Liste in der Datei package.xml zu finden ist .

    Jetzt werde ich Ihnen die wichtigsten Änderungen in der Funktionalität erläutern.

    Funktionen und Methoden

    Verschlüsse

    Ab PHP 5.3 unterstützen die Funktionen runkit_function_add, runkit_function_redefine, runkit_method_add und runkit_method_redefine das Schließen als Parameter. Wenn Sie beispielsweise früher eine Funktion neu definieren wollten, mussten Sie einen Ausdruck des Formulars schreiben

    runkit_function_redefine('sprintf', '$s', 'return $s;');
    

    Das hat eval benutzt, um einen String in Bytecode zu verwandeln, der sehr langsam ist. Jetzt können Sie schreiben

    runkit_function_redefine('sprintf', function($s) {return $s;});
    

    Gleichzeitig wird keine Auswertung durchgeführt, und die Pflege dieses Codes ist viel einfacher - es gibt keine Programmteile mehr in String-Literalen! Gleiches gilt für die Funktionen runkit_function_add, runkit_method_add und runkit_method_redefine.

    Magische Methoden

    In Runkit werden jetzt auch Manipulationen mit den magischen Methoden __get, __set, __isset, __unset, __clone, __call, __callStatic, serialize, unserialize, __debugInfo und __toString vollständig unterstützt. Gleiches gilt für Konstruktoren und Destruktoren, sowohl mit der modernen Benennungsmethode als auch mit der Benennung im Stil von PHP4.

    Doc-Kommentare

    Wenn Sie jetzt Methoden und Funktionen mit der alten Syntax hinzufügen oder überschreiben (wenn die Argumente der neuen Funktion und ihr Text in Zeichenfolgen übergeben werden), können Sie doc-comments angeben. Zu diesem Zweck haben die Funktionen runkit_function_add, runkit_function_redefine, runkit_method_add und runkit_method_redefine ein neues optionales Argument (letzte Reihenfolge) - doc_comment:

    runkit_method_redefine('MyClass','myMethod', '$arg', 'return $arg',  RUNKIT_ACC_PRIVATE, 'my doc_comment'); // переопределяет приватный метод с doc-comment’ом
    runkit_method_add('MyClass','myMethod2', '$arg', 'return $arg',  NULL, 'my doc_comment2'); // добавляет приватный метод с doc-comment’ом
    

    Beim Definieren von Funktionen und Methoden im neuen Stil (durch Schließen) können Dokumentkommentare auf dieselbe Weise wie beim Definieren gewöhnlicher Funktionen angegeben werden - durch Kommentare zum Funktionskörper. Beide Methoden können kombiniert werden - die Priorität ist für Dokumentkommentare, die als Argument übergeben werden. Außerdem wurde das Anhängen von Dokument-Kommentaren beim Vererben, Kopieren und Umbenennen von Methoden und Funktionen behoben.

    Rückgabewerte als Referenz

    Es wurde die Möglichkeit hinzugefügt, Funktionen und Methoden hinzuzufügen und neu zu definieren, sodass eine neue Funktion (oder Methode) einen Wert als Referenz zurückgibt. Damit die neue Funktion, die mit der alten Syntax angegeben wurde (wenn die Argumente der neuen Funktion und ihr Body in Strings übergeben werden), einen Referenzwert zurückgibt, müssen Sie ein neues Argument an die Funktion runkit_function_add (oder runkit_function_redefine) - return_ref - mit dem Wert TRUE übergeben. Zum Beispiel

    runkit_function_redefine('my_function', '$a', 'return $a;', TRUE); // возвращает значение по ссылке
    

    Wenn die Methode auf die gleiche Weise hinzugefügt (oder neu definiert) wird, wird das flags-Argument mit gesetztem RUNKIT_ACC_RETURN_REFERENCE-Bit verwendet. Zum Beispiel

    runkit_method_redefine('MyClass', 'myMethod', '$a', 'return $a;', RUNKIT_ACC_PROTECTED | RUNKIT_ACC_RETURN_REFERENCE); // protected-метод возвращает значение по ссылке
    

    Wenn Sie eine Funktion oder Methode mit der neuen Syntax definieren (über Closures), benötigen Sie nicht alle diese Flags. Fügen Sie einfach ein kaufmännisches Und vor die Liste der Funktionsargumente ein:

    runkit_function_redefine('my_function', function &($a) {return $a;}); // возвращает значение по ссылке
    

    Klasseneigenschaften

    Die interne Implementierung der Manipulation von Klasseneigenschaften wurde komplett überarbeitet. Das Hinzufügen, Löschen und Importieren von Klasseneigenschaften wirkt sich jetzt korrekt auf untergeordnete Klassen aus. Darüber hinaus können sich diese Aktionen jetzt auf die Objekte der Klasse und ihrer Nachkommen auswirken. Um diesen Effekt zu aktivieren, müssen Sie das RUNKIT_OVERRIDE_OBJECTS-Bit im flags-Argument setzen, wenn Sie die Funktionen runkit_default_property_add und runkit_default_property_redefine aufrufen. Zum Beispiel

    runkit_default_property_add('MyClass', 'newProperty', 'value'); // не влияет на объекты класса и его потомков
    runkit_default_property_add('MyClass', 'newProperty', 'value', RUNKIT_OVERRIDE_OBJECTS); // добавит свойство не только в классы и классы-потомки, но и в их объекты
    

    Gleiches gilt für den Import von Klasseneigenschaften:

    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASS_PROPS); // импортирует свойства классов, не переопределяя существующие свойства и не затрагивая объекты
    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASS_PROPS | RUNKIT_IMPORT_OVERRIDE); // импортирует свойства классов, переопределяя существующие свойства, но не затрагивая объекты
    runkit_import('myfile.inc', RUNKIT_IMPORT_CLASS_PROPS | RUNKIT_IMPORT_OVERRIDE | RUNKIT_OVERRIDE_OBJECTS); // импортирует свойства классов, переопределяя существующие свойства и изменяя свойства в объектах
    

    Außerdem wurde eine neue Funktion runkit_default_property_remove () hinzugefügt, um Eigenschaften aus Klassen zu entfernen. Um eine Eigenschaft nicht nur aus einer Klasse, sondern auch aus ihren Objekten zu entfernen, verfügt die Funktion runkit_default_property_remove über einen dritten optionalen Parameter:

    runkit_default_property_remove('MyClass', 'myProperty'); // удаляет свойство из класса, но оставляет его в объектах
    runkit_default_property_remove('MyClass', 'myProperty', TRUE); // удаляет свойство из класса и из его объектов
    

    Beim Hinzufügen und Überschreiben von Klasseneigenschaften können Sie jetzt nicht nur skalare Werte, sondern auch Arrays verwenden.

    Klassen

    Zuvor hatten die Funktionen runkit_class_adopt und runkit_class_emancipate, obwohl sie den Inhalt von Klassen änderten, keinen Einfluss auf ihre Hierarchie (d. H. Nach dem Anwenden von runkit_class_adopt hatte die Klasse formal noch kein Elternteil und nach runkit_class_emancipate blieb das Elternteil weiterhin). Dies wurde nun behoben.

    Groß- und Kleinschreibung in Entitätsnamen und Namespaces

    Das Arbeiten mit Konstanten, Funktionen, Methoden und Eigenschaften unterstützt jetzt Namespaces in vollem Umfang. Runkit senkte auch nicht mehr die Namen der Eigenschaften, Klassen, Methoden und Funktionen, die es erstellt (wie zuvor).

    Zusätzliche Sandkastensicherheit

    Für Runkit_Sandbox-Sandboxes können Sie jetzt die INI-Einstellung allow_url_include deaktivieren. Unabhängig von der Plattform unterstützt die Konfiguration von open_basedir jetzt auch Pfadlisten (zuvor konnte nur ein Pfad eingegeben werden).

    Aktualisierungen

    Das Aktualisieren von Runkit ist jetzt viel einfacher. Dies kann nun auf die übliche Weise für alle PECL-Benutzer über den offiziellen Kanal pecl.php.net erfolgen . Um die neueste Version von Runkit zu installieren, wählen Sie einfach

    pecl install runkit
    

    Außerdem sind alle Veröffentlichungsarchive jetzt unter http://pecl.php.net/runkit verfügbar .

    Fazit


    Mittlerweile wird Runkit in vielen namhaften Unternehmen und Projekten auf der ganzen Welt für Unit-Tests sowie für viele andere Aufgaben eingesetzt. Ich bin sicher, dass ihm eine große Zukunft bevorsteht. Möglich wird dies durch Spenden, die jetzt mit einem Klick von der Projektseite github.com/zenovich/runkit oder direkt von phpinfo () aus getätigt werden können.

    Vielen Dank!

    Jetzt auch beliebt: