
Verwenden Sie zum Debuggen von PHP-Programmen häufig Xdebug . Die Standardfunktionen von IDE und Xdebug reichen jedoch nicht immer aus. Einige der Probleme können mit dem Xdebug-Proxy - pydbgpproxy - gelöst werden, aber immer noch nicht alle. Daher habe ich den PHP Xdebug-Proxy basierend auf dem asynchronen Amphp-Framework implementiert.
Unter dem Schnitt werde ich Ihnen sagen, was mit pydbgpproxy nicht stimmt, was darin fehlt und warum ich es nicht geändert habe. Ich werde auch anhand eines Beispiels erklären, wie der PHP Xdebug-Proxy funktioniert, und zeigen, wie er erweitert werden kann.
Pydbgpproxy vs PHP Xdebug Proxy
Der Xdebug-Proxy ist ein Zwischendienst zwischen der IDE und Xdebug (Proxy-Anforderungen von Xdebug an die IDE und umgekehrt). Am häufigsten wird es für das Mehrbenutzer-Debugging verwendet . Dies ist der Fall, wenn Sie einen Webserver und mehrere Entwickler haben.
Als Proxy wird normalerweise pydbgpproxy verwendet. Aber er hat ein paar Probleme:
- keine offizielle Seite;
- schwer zu finden, wo man es herunterladen kann; Es stellt sich heraus, dass dies hier möglich ist - plötzlich Python Remote Debugging Client;
- Ich habe das offizielle Repository nicht gefunden.
- Infolge des vorherigen Absatzes ist nicht klar, wohin die Pull-Anfrage gebracht werden soll.
- Proxy ist, wie der Name schon sagt, in Python geschrieben, was nicht allen PHP-Entwicklern bekannt ist, was bedeutet, dass die Erweiterung ein Problem darstellt.
- Fortsetzung des vorherigen Absatzes: Wenn in PHP Code vorhanden ist und dieser im Proxy verwendet werden muss, muss er nach Python portiert werden, und das Duplizieren von Code ist immer nicht sehr gut.
Eine Suche nach einem Xdebug-Proxy, der in PHP auf GitHub und im Internet geschrieben wurde, ergab keine Ergebnisse. Also habe ich den PHP Xdebug Proxy geschrieben . Unter der Haube habe ich das asynchrone Amphp- Framework verwendet.
Die Hauptvorteile von PHP Xdebug Proxy gegenüber Pydbgpproxy:
- Der PHP Xdebug-Proxy ist in einer Sprache geschrieben, die PHP-Entwicklern vertraut ist. Dies bedeutet:
- es ist einfacher, Probleme darin zu lösen;
- es ist einfacher zu erweitern;
- Der PHP Xdebug-Proxy verfügt über ein öffentliches Repository. Dies bedeutet:
- Sie können es nach Ihren Wünschen teilen und fertigstellen.
- Sie können eine Pull-Anfrage mit einer fehlenden Funktion oder einer Lösung für ein Problem senden.
So arbeiten Sie mit dem PHP Xdebug-Proxy
Installation
Der PHP Xdebug-Proxy kann über Composer als Entwicklungsabhängigkeit installiert werden:
composer.phar require mougrim/php-xdebug-proxy --dev
Wenn Sie jedoch keine zusätzlichen Abhängigkeiten in Ihr Projekt ziehen möchten, kann der PHP Xdebug-Proxy über denselben Composer als Projekt installiert werden:
composer.phar create-project mougrim/php-xdebug-proxy cd php-xdebug-proxy
Der PHP Xdebug-Proxy ist erweiterbar, aber ext-dom ist standardmäßig erforderlich (die Erweiterung ist in PHP standardmäßig aktiviert), um XML und amphp / log für die asynchrone Protokollierung zu analysieren :
composer.phar require amphp/log '^1.0.0'
Starten

Der Proxy startet wie folgt:
bin/xdebug-proxy
Der Proxy beginnt mit den Standardeinstellungen:
Using config path /path/to/php-xdebug-proxy/config [2019-02-14 10:46:24] xdebug-proxy.NOTICE: Use default ide: 127.0.0.1:9000 array ( ) array ( ) [2019-02-14 10:46:24] xdebug-proxy.NOTICE: Use predefined ides array ( 'predefinedIdeList' => array ( 'idekey' => '127.0.0.1:9000', ), ) array ( ) [2019-02-14 10:46:24] xdebug-proxy.NOTICE: [Proxy][IdeRegistration] Listening for new connections on '127.0.0.1:9001'... array ( ) array ( ) [2019-02-14 10:46:24] xdebug-proxy.NOTICE: [Proxy][Xdebug] Listening for new connections on '127.0.0.1:9002'... array ( ) array ( )
Aus dem Protokoll können Sie ersehen, dass der Standard-Proxy:
- lauscht auf
127.0.0.1:9001
für IDE-Anmeldeverbindungen; - lauscht auf
127.0.0.1:9002
für Xdebug-Verbindungen; - verwendet
127.0.0.1:9000
als Standard-IDE und vordefinierte IDE mit Idekey-Schlüssel.
Konfiguration
Wenn Sie Überwachungsports usw. konfigurieren möchten, können Sie den Pfad zum Einstellungsordner angeben. Kopieren Sie einfach den Konfigurationsordner :
cp -r /path/to/php-xdebug-proxy/config /your/custom/path
Der Einstellungsordner enthält drei Dateien:
Nach dem Kopieren der Dateien können Sie den Proxy bearbeiten und ausführen:
bin/xdebug-proxy --configs=/your/custom/path/config
Debuggen
Es wurden viele Artikel zum Debuggen von Code mit Xdebug geschrieben. Ich werde die Hauptpunkte beachten.
In der php.ini sollten sich die folgenden Einstellungen im Abschnitt [xdebug]
(korrigieren Sie sie, wenn sie von den Standardeinstellungen abweichen):
- idekey = idekey
- remote_host = 127.0.0.1
- remote_port = 9002
- remote_enable = Ein
- remote_autostart = Ein
- remote_connect_back = Aus
Dann können Sie debuggten PHP-Code ausführen:
php /path/to/your/script.php
Wenn Sie alles richtig gemacht haben, beginnt das Debuggen am ersten Haltepunkt in der IDE. Das Debuggen im PHP-Fpm-Modus durch mehrere Entwickler geht über den Rahmen dieses Artikels hinaus, wird jedoch beispielsweise hier beschrieben .
Erweiterungs-Proxy-Funktionen
Alles, was wir oben untersucht haben, ist auch Pydbgpproxy bis zu dem einen oder anderen Grad.
Lassen Sie uns nun über den interessantesten PHP Xdebug-Proxy sprechen. Proxies können mit Ihrer eigenen Factory erweitert werden (erstellt in der Konfiguration factory.php
, siehe oben). Die Factory muss die Factory\Factory
Schnittstelle implementieren.
Am mächtigsten sind die sogenannten Request Preparer. Sie können Anforderungen von Xdebug an die IDE ändern und umgekehrt. Um einen Factory\DefaultFactory::createRequestPreparers()
hinzuzufügen, müssen Sie die Factory\DefaultFactory::createRequestPreparers()
-Methode Factory\DefaultFactory::createRequestPreparers()
. Die Methode gibt ein Array von Objekten zurück, die die Schnittstelle RequestPreparer\RequestPreparer
implementieren. Wenn eine Anforderung von Xdebug an die IDE weitergeleitet wird, werden sie in der direkten Reihenfolge ausgeführt. Wenn Sie eine Anforderung von der IDE an Xdebug weiterleiten, wird sie umgekehrt.
Abfragehandler können beispielsweise verwendet werden, um Pfade zu Dateien zu ändern (in Haltepunkten und ausführbaren Dateien).
Debuggen Sie überschriebene Dateien
Um ein Beispiel für einen Vorbereiter zu geben, werde ich einen kleinen Exkurs machen. In Unit-Tests verwenden wir Soft-Mocks ( GitHub ). Mit Soft-Mocks können Sie Funktionen, statische Methoden, Konstanten usw. in Tests ersetzen . Dies ist eine Alternative für Runkit und Uopz . Dies funktioniert, indem PHP-Dateien im laufenden Betrieb neu geschrieben werden. Ebenso funktioniert AspectMock immer noch.
Mit den Standardfunktionen von Xdebug und IDE können Sie jedoch das neu geschriebene Debugging (mit einem anderen Pfad) anstelle der Originaldateien debuggen.
Schauen wir uns das Debugging-Problem mit Soft-Mocks in Tests genauer an. Nehmen Sie zunächst den Fall, in dem der PHP-Code lokal ausgeführt wird.
Die ersten Schwierigkeiten treten beim Festlegen von Haltepunkten (Haltepunkten) auf. In der IDE werden sie in den Originaldateien installiert, nicht in den neu geschriebenen. Um einen Haltepunkt durch die IDE zu setzen, müssen Sie die tatsächlich neu geschriebene Datei finden. Das Problem wird durch die Tatsache verschärft, dass jedes Mal, wenn die Originaldatei geändert wird, eine neue neu geschriebene Datei erstellt wird, dh für jeden eindeutigen Dateiinhalt wird eine eindeutige neu geschriebene Datei erstellt.
Dieses Problem kann durch Aufrufen der Funktion xdebug_break()
gelöst werden, die dem Festlegen eines Haltepunkts ähnelt. In diesem Fall muss nicht nach einer neu geschriebenen Datei gesucht werden.
Betrachten Sie die Situation nun als komplizierter: Die Anwendung wird auf einem Remotecomputer ausgeführt.
In diesem Fall können Sie den Ordner mit den neu geschriebenen Dateien beispielsweise über SSHFS bereitstellen. Wenn sich die lokalen und Remote-Pfade zum Ordner unterscheiden, müssen Sie weiterhin Zuordnungen in der IDE registrieren.
Auf die eine oder andere Weise unterscheidet sich diese Methode geringfügig von der üblichen und ermöglicht es Ihnen, nur die kopierten Dateien zu debuggen, nicht jedoch die Originaldateien. Trotzdem möchte ich dieselben Originaldateien bearbeiten und debuggen.
AspectMock hat das Problem umgangen, indem es den Debug-Modus aktiviert hat, ohne ihn deaktivieren zu können:
public function init(array $options = []) { if (!isset($options['excludePaths'])) { $options['excludePaths'] = []; } $options['debug'] = true; $options['excludePaths'][] = __DIR__; parent::init($options); }
In einem einfachen Testbeispiel ist der Debug-Modus um 20 Prozent langsamer. Ich habe jedoch nicht genügend AspectMock-Tests, um genauer abzuschätzen, wie langsam er ist. Wenn Sie viele Tests mit AspectMock haben, würde ich mich freuen, wenn Sie den Vergleich in den Kommentaren teilen.
Verwenden von Xdebug mit Soft-Mocks

Nachdem das Problem klar ist, überlegen Sie, wie Sie es mit dem PHP Xdebug-Proxy lösen können. Der Hauptteil befindet sich in der RequestPreparer\SoftMocksRequestPreparer
.
Definieren Sie im Klassenkonstruktor den Pfad zum Soft-Mocks-Initialisierungsskript und führen Sie ihn aus (es wird davon ausgegangen, dass Soft-Mocks als Abhängigkeit verbunden sind, aber jeder Pfad kann an den Konstruktor übergeben werden):
public function __construct(LoggerInterface $logger, string $initScript = '') { $this->logger = $logger; if (!$initScript) { $possibleInitScriptPaths = [

Um eine Anforderung von Xdebug an die IDE vorzubereiten, müssen Sie den Pfad zur neu geschriebenen Datei durch die Originaldatei ersetzen:
public function prepareRequestToIde(XmlDocument $xmlRequest, string $rawRequest): void { $context = [ 'request' => $rawRequest, ]; $root = $xmlRequest->getRoot(); if (!$root) { return; } foreach ($root->getChildren() as $child) {

Um eine Anforderung von der IDE an Xdebug vorzubereiten, müssen Sie den Pfad zur Originaldatei durch den Pfad zur neu geschriebenen ersetzen:
public function prepareRequestToXdebug(string $request, CommandToXdebugParser $commandToXdebugParser): string {
Damit der Factory\DefaultFactory
funktioniert, müssen Sie Ihre Factory-Klasse erstellen und entweder von Factory\DefaultFactory
erben oder die Factory\Factory
Schnittstelle implementieren. Für Soft-Mocks sieht die Factory\SoftMocksFactory
aus:
class SoftMocksFactory extends DefaultFactory { public function createConfig(array $config): Config {
Hier benötigen Sie eine eigene Konfigurationsklasse, damit Sie den Pfad des Soft-Mocks-Init-Skripts angeben können. Was es ist, können Sie in Config \ SoftMocksConfig sehen .
Es blieb nur wenig übrig: eine neue Factory zu erstellen und den Pfad zum Soft-Mocks-Init-Skript anzugeben. Wie das geht, kann in softMocksConfig
eingesehen softMocksConfig
.
Nicht blockierende API
Wie ich oben geschrieben habe, verwendet der PHP Xdebug-Proxy Amphp unter der Haube, was bedeutet, dass eine nicht blockierende API verwendet werden muss, um mit E / A zu arbeiten. Apmphp verfügt bereits über viele Komponenten, die diese nicht blockierende API implementieren. Wenn Sie den PHP Xdebug-Proxy erweitern und im Mehrbenutzermodus verwenden möchten, müssen Sie nicht blockierende APIs verwenden.
Schlussfolgerungen
PHP Xdebug Proxy ist noch ein relativ junges Projekt, aber in Badoo wird es bereits aktiv zum Debuggen von Tests mit Soft-Mocks verwendet.
PHP Xdebug-Proxy:
- ersetzt pydbgpproxy beim Debuggen für mehrere Benutzer;
- kann mit Soft-Mocks arbeiten;
- kann erweitert werden:
- Sie können die Pfade zu Dateien ersetzen, die von der IDE und von Xdebug stammen.
- Statistiken können gesammelt werden: Im Debug-Modus ist beim Debuggen mindestens der ausführbare Kontext verfügbar (Werte von Variablen und ausführbare Codezeile).
Wenn Sie den Xdebug-Proxy für etwas anderes als das Mehrbenutzer-Debugging verwenden, teilen Sie Ihren Fall und den Xdebug-Proxy, den Sie in den Kommentaren verwenden.
Wenn Sie pydbgpproxy oder einen anderen Xdebug-Proxy verwenden, versuchen Sie es mit dem PHP Xdebug-Proxy, informieren Sie sich über Ihre Probleme und teilen Sie Pull-Anforderungen. Lassen Sie uns das Projekt gemeinsam entwickeln! :) :)
PS Vielen Dank an meinen Kollegen Yevgeny Makhrov aka eZH für die Idee von Proxy smdbgpproxy !
Wieder Links
- PHP Xdebug-Proxy - Xdebug-Proxy, der im Artikel behandelt wird;
- pydbgpproxy kann hier heruntergeladen werden - plötzlich Python Remote Debugging Client;
- amphp - asynchrones nicht blockierendes PHP-Framework;
- Werkzeuge für Mock-s:
Vielen Dank für Ihre Aufmerksamkeit!
Ich freue mich über Kommentare und Vorschläge.
Rinat Akhmadeev, Sr. PHP-Entwickler
UPD : Veröffentlichte Übersetzung des Artikels ins Englische.