
Para la depuración, los programas PHP a menudo usan Xdebug . Sin embargo, las características estándar del IDE y Xdebug no siempre son suficientes. Algunos de los problemas pueden resolverse utilizando el proxy Xdebug - pydbgpproxy, pero aún no todos. Por lo tanto, implementé el proxy PHP Xdebug basado en el marco asincrónico amphp.
Debajo del corte, le diré lo que está mal con pydbgpproxy, lo que falta y por qué no lo modifiqué. También explicaré cómo funciona el proxy Xdebug de PHP y mostraré cómo extenderlo con un ejemplo.
Pydbgpproxy vs proxy PHP Xdebug
El proxy Xdebug es un servicio intermedio entre el IDE y Xdebug (solicitudes de proxy de Xdebug al IDE y viceversa). Muy a menudo se utiliza para la depuración multiusuario . Esto es cuando tienes un servidor web y varios desarrolladores.
Como proxy, generalmente se usa pydbgpproxy. Pero tiene algunos problemas:
- sin página oficial;
- difícil de encontrar donde descargarlo; Resulta que esto se puede hacer aquí : de repente, el cliente de depuración remota de Python;
- No encontré el repositorio oficial;
- como consecuencia del párrafo anterior, no está claro dónde llevar la solicitud de extracción;
- proxy, como su nombre lo indica, está escrito en Python, que no todos los desarrolladores de PHP saben, lo que significa que expandirlo es un problema;
- continuación del párrafo anterior: si hay algún código en PHP, y necesitará usarse en proxy, entonces tendrá que ser portado a Python, y la duplicación de código siempre no es muy buena.
La búsqueda de un proxy Xdebug escrito en PHP en GitHub y en Internet no arrojó resultados. Entonces escribí el proxy Xdebug de PHP . Debajo del capó, utilicé el marco asincrónico amphp .
Las principales ventajas del proxy PHP Xdebug sobre pydbgpproxy:
- El proxy PHP Xdebug está escrito en un lenguaje familiar para los desarrolladores de PHP, lo que significa:
- es más fácil resolver problemas en él;
- es más fácil de expandir;
- El proxy PHP Xdebug tiene un repositorio público, lo que significa:
- Puede bifurcarlo y terminarlo según sus necesidades;
- Puede enviar una solicitud de extracción con una función faltante o una solución a un problema.
Cómo trabajar con proxy Xdebug de PHP
Instalación
El proxy PHP Xdebug se puede instalar como una dependencia de desarrollo a través del compositor :
composer.phar require mougrim/php-xdebug-proxy --dev
Pero si no desea arrastrar dependencias adicionales a su proyecto, entonces el proxy Xdebug de PHP se puede instalar como un proyecto a través del mismo compositor:
composer.phar create-project mougrim/php-xdebug-proxy cd php-xdebug-proxy
El proxy Xdebug de PHP es extensible, pero se requiere ext-dom de forma predeterminada (la extensión está habilitada de forma predeterminada en PHP) para analizar XML y amphp / log para el registro asincrónico:
composer.phar require amphp/log '^1.0.0'
Lanzamiento

El proxy comienza de la siguiente manera:
bin/xdebug-proxy
Proxy comenzará con la configuración predeterminada:
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 ( )
Desde el registro puede ver que el proxy predeterminado:
- escucha
127.0.0.1:9001
para conexiones de inicio de sesión IDE; - escucha
127.0.0.1:9002
para conexiones Xdebug; - utiliza
127.0.0.1:9000
como IDE predeterminado e IDE predefinido con la clave idekey.
Configuracion
Si desea configurar puertos de escucha, etc., puede especificar la ruta a la carpeta de configuración. Simplemente copie la carpeta de configuración :
cp -r /path/to/php-xdebug-proxy/config /your/custom/path
Hay tres archivos en la carpeta de configuración:
Después de copiar los archivos, puede editar y ejecutar el proxy:
bin/xdebug-proxy --configs=/your/custom/path/config
Depuración
Se han escrito muchos artículos sobre cómo depurar código usando Xdebug. Anotaré los puntos principales.
En php.ini, las siguientes configuraciones deben estar en la sección [xdebug]
( [xdebug]
si difieren de las estándar):
- idekey = idekey
- remote_host = 127.0.0.1
- remote_port = 9002
- remote_enable = On
- remote_autostart = On
- remote_connect_back = Apagado
Luego puede ejecutar el código PHP depurado:
php /path/to/your/script.php
Si hizo todo bien, la depuración comenzará desde el primer punto de interrupción en el IDE. La depuración en modo php-fpm por parte de varios desarrolladores está más allá del alcance de este artículo, pero se describe, por ejemplo, aquí .
Funciones de proxy de extensión
Todo lo que examinamos anteriormente, pydbgpproxy también es capaz de un grado u otro.
Ahora hablemos de lo más interesante en PHP Xdebug proxy. Los proxies se pueden ampliar utilizando su propia fábrica (creada en la configuración factory.php
, ver arriba). La fábrica debe implementar la interfaz Factory\Factory
.
Los más poderosos son los llamados preparadores de solicitudes. Pueden modificar las solicitudes de Xdebug al IDE y viceversa. Para agregar un Factory\DefaultFactory::createRequestPreparers()
consultas, debe anular el método Factory\DefaultFactory::createRequestPreparers()
. El método devuelve una matriz de objetos que implementan la interfaz RequestPreparer\RequestPreparer
. Al enviar una solicitud de Xdebug al IDE, se ejecutan en el orden directo; al enviar una solicitud del IDE a Xdebug, se invierte.
Los manejadores de consultas se pueden usar, por ejemplo, para cambiar rutas a archivos (en puntos de interrupción y archivos ejecutables).
Depurar archivos sobrescritos
Para dar un ejemplo de preparador, haré una pequeña digresión. En las pruebas unitarias, utilizamos simulacros ( GitHub ). Soft-mocks le permite reemplazar funciones, métodos estáticos, constantes, etc. en las pruebas, es una alternativa para runkit y uopz . Esto funciona reescribiendo archivos PHP sobre la marcha. Del mismo modo, AspectMock todavía funciona.
Pero las características estándar de Xdebug e IDE le permiten depurar reescritas (que tienen una ruta diferente), en lugar de los archivos originales.
Echemos un vistazo más de cerca al problema de depuración usando simulacros en las pruebas. Primero, tome el caso donde el código PHP se ejecuta localmente.
Las primeras dificultades aparecen en la etapa de establecer puntos de interrupción (puntos de interrupción). En el IDE, se instalan en los archivos originales, no en los reescritos. Para poner un punto de interrupción a través del IDE, debe encontrar el archivo reescrito real. El problema se agrava por el hecho de que cada vez que se cambia el archivo original, se crea un nuevo archivo reescrito, es decir, para cada contenido de archivo único habrá un archivo reescrito único.
Este problema se puede resolver llamando a la función xdebug_break()
, que es similar a establecer un punto de interrupción. En este caso, no hay necesidad de buscar un archivo reescrito.
Ahora considere la situación más complicada: la aplicación se ejecuta en una máquina remota.
En este caso, puede montar la carpeta con los archivos reescritos, por ejemplo, a través de SSHFS. Si las rutas locales y remotas a la carpeta son diferentes, aún debe registrar las asignaciones en el IDE.
De una forma u otra, este método es ligeramente diferente del habitual y le permite depurar solo los archivos copiados, pero no los originales. Pero aún así quiero editar y depurar los mismos archivos originales.
AspectMock solucionó el problema al habilitar el modo de depuración sin la capacidad de deshabilitarlo:
public function init(array $options = []) { if (!isset($options['excludePaths'])) { $options['excludePaths'] = []; } $options['debug'] = true; $options['excludePaths'][] = __DIR__; parent::init($options); }
En un ejemplo de prueba simple, el modo de depuración es más lento en un 20 por ciento, pero no tengo suficientes pruebas de AspectMock para dar una estimación más precisa de lo lento que es. Si tiene muchas pruebas en AspectMock, me alegrará si comparte la comparación en los comentarios.
Usando Xdebug con simulacros

Ahora que el problema está claro, considere cómo resolverlo utilizando el proxy Xdebug de PHP. La parte principal está en la RequestPreparer\SoftMocksRequestPreparer
.
En el constructor de la clase, defina la ruta al script de inicialización de simulacros blandos y ejecútelo (se supone que los simulacros blandos están conectados como una dependencia, pero se puede pasar cualquier ruta al constructor):
public function __construct(LoggerInterface $logger, string $initScript = '') { $this->logger = $logger; if (!$initScript) { $possibleInitScriptPaths = [

Para preparar una solicitud de Xdebug al IDE, debe reemplazar la ruta al archivo reescrito con el archivo original:
public function prepareRequestToIde(XmlDocument $xmlRequest, string $rawRequest): void { $context = [ 'request' => $rawRequest, ]; $root = $xmlRequest->getRoot(); if (!$root) { return; } foreach ($root->getChildren() as $child) {

Para preparar una solicitud del IDE a Xdebug, debe reemplazar la ruta al archivo original con la ruta a la reescrita:
public function prepareRequestToXdebug(string $request, CommandToXdebugParser $commandToXdebugParser): string {
Para que el Factory\DefaultFactory
consultas funcione, debe crear su clase de fábrica y heredarla de Factory\DefaultFactory
, o implementar la interfaz Factory\Factory
. Para los Factory\SoftMocksFactory
, la Factory\SoftMocksFactory
ve así:
class SoftMocksFactory extends DefaultFactory { public function createConfig(array $config): Config {
Aquí necesita su propia clase de configuración para que pueda especificar la ruta del script de inicio de simulacros. Lo que es, puede ver en Config \ SoftMocksConfig .
Solo quedaba un poco: crear una nueva fábrica e indicar la ruta al script de inicio de simulacros. Cómo se hace esto se puede ver en softMocksConfig
.
API sin bloqueo
Como escribí anteriormente, el proxy Xdebug de PHP usa amphp debajo del capó, lo que significa que se debe usar una API sin bloqueo para trabajar con E / S. Apmphp ya tiene muchos componentes que implementan esta API sin bloqueo. Si va a extender el proxy PHP Xdebug y usarlo en modo multiusuario, asegúrese de usar API sin bloqueo.
Conclusiones
El proxy PHP Xdebug todavía es un proyecto bastante joven, pero en Badoo ya se usa activamente para depurar pruebas usando simulacros.
Proxy PHP Xdebug:
- reemplaza pydbgpproxy en la depuración multiusuario;
- puede trabajar con simulacros blandos;
- se puede ampliar:
- Puede reemplazar las rutas a los archivos que provienen del IDE y de Xdebug;
- se pueden recopilar estadísticas: en modo de depuración, al menos el contexto ejecutable está disponible al depurar (valores de variables y línea de código ejecutable).
Si usa el proxy Xdebug para algo que no sea la depuración multiusuario, comparta su caso y el proxy Xdebug que usa en los comentarios.
Si usa pydbgpproxy o algún otro proxy Xdebug, pruebe el proxy Xdebug de PHP, informe sobre sus problemas, comparta solicitudes de extracción. ¡Desarrollemos el proyecto juntos! :)
PD: ¡Gracias a mi colega Yevgeny Makhrov, también conocido como eZH, por la idea de proxy smdbgpproxy !
Enlaces de nuevo
- Proxy Xdebug de PHP: proxy Xdebug, que se trata en el artículo;
- pydbgpproxy se puede descargar aquí , de repente, Python Remote Debugging Client;
- amphp : marco PHP asincrónico sin bloqueo;
- herramientas para simulacros:
Gracias por su atencion!
Estaré encantado de comentarios y sugerencias.
Rinat Akhmadeev, Sr. Desarrollador PHP
UPD : Traducción publicada del artículo al inglés.