composer/xdebug-handler

重启进程而不启用Xdebug。

安装数: 280 162 527

依赖者: 86

建议者: 1

安全性: 0

星标: 2 508

关注者: 10

分支: 40

开放问题: 0

3.0.5 2024-05-06 16:37 UTC

README

packagist Continuous Integration license php

除非 xdebug.mode=off,否则在加载Xdebug扩展的情况下重启CLI进程。

最初作为composer/composer的一部分编写,现在已提取并作为独立的库提供。

版本 3

移除了对旧版PHP版本的支持,并添加了类型声明。

对版本 2 (PHP 5.3.2 - 7.2.4) 的长期支持遵循Composer 2.2 LTS策略。

安装

使用以下命令安装最新版本

$ composer require composer/xdebug-handler

要求

  • 最低PHP版本7.2.5,尽管强烈推荐使用最新的PHP版本。

基本用法

use Composer\XdebugHandler\XdebugHandler;

$xdebug = new XdebugHandler('myapp');
$xdebug->check();
unset($xdebug);

构造函数接受一个参数$envPrefix,它被转换为大写并附加到默认的基本值之前,以创建两个不同的环境变量。上述示例启用了对以下内容的访问

  • MYAPP_ALLOW_XDEBUG=1 以覆盖自动重启并允许Xdebug
  • MYAPP_ORIGINAL_INIS 以在重启的进程中获得ini文件位置

高级用法

工作原理

从加载(并扫描)的ini文件创建一个临时ini文件,任何对Xdebug扩展的引用都被注释掉。当前ini设置将被合并,因此大多数在命令行或应用程序中设置的ini设置都将包括在内(见限制

  • MYAPP_ALLOW_XDEBUG 通过内部数据设置,以标记并用于重启。
  • 为重启配置命令行和环境。
  • 在新的进程中重启应用程序。
    • 重启设置存储在环境中。
    • MYAPP_ALLOW_XDEBUG 被取消设置。
    • 应用程序运行并退出。
  • 主进程以重启进程的退出代码退出。

有关更多信息,请参阅示例

信号处理

如果加载了pcntl扩展,则自动启用异步信号处理。SIGINT 在父进程中设置为SIG_IGN,在重启的进程中恢复为SIG_DFL(如果没有设置其他处理程序)。

从PHP 7.4开始,在Windows上自动启用重启进程中的CTRL+CCTRL+BREAK处理,并在父进程中忽略。

限制

在重启进程中运行时需要注意以下几点。

  • 命令行上设置的扩展将不会被加载。
  • ini文件位置将按照重启方式报告 - 请参阅getAllIniFiles()
  • Php子进程可能已启用Xdebug加载 - 请参阅进程配置

辅助方法

这些静态方法提供有关当前进程的信息,无论它是否已重启。

getAllIniFiles(): array

返回原始ini文件位置的数组。使用此方法代替调用php_ini_loaded_filephp_ini_scanned_files,这些方法在重启的进程中将报告错误值。

use Composer\XdebugHandler\XdebugHandler;

$files = XdebugHandler::getAllIniFiles();

# $files[0] always exists, it could be an empty string
$loadedIni = array_shift($files);
$scannedInis = $files;

这些位置也包含在MYAPP_ORIGINAL_INIS环境变量中。这是一个由路径分隔的字符串,包含来自php_ini_loaded_file返回的位置(可能为空),然后是来自php_ini_scanned_files解析的位置。

getRestartSettings(): ?array

返回一个可以用于PHP 子进程的设置数组,如果没有重启进程,则返回null。

use Composer\XdebugHandler\XdebugHandler;

$settings = XdebugHandler::getRestartSettings();
/**
 * $settings: array (if the current process was restarted,
 * or called with the settings from a previous restart), or null
 *
 *    'tmpIni'      => the temporary ini file used in the restart (string)
 *    'scannedInis' => if there were any scanned inis (bool)
 *    'scanDir'     => the original PHP_INI_SCAN_DIR value (false|string)
 *    'phprc'       => the original PHPRC value (false|string)
 *    'inis'        => the original inis from getAllIniFiles (array)
 *    'skipped'     => the skipped version from getSkippedVersion (string)
 */

getSkippedVersion(): string

返回重启过程中跳过的Xdebug版本字符串,如果没有重启(或Xdebug仍然加载,可能是通过扩展类以其他原因重启而不是移除Xdebug),则返回空字符串。

use Composer\XdebugHandler\XdebugHandler;

$version = XdebugHandler::getSkippedVersion();
# $version: '3.1.1' (for example), or an empty string

isXdebugActive(): bool

如果Xdebug已加载并且在活动模式下运行(如果它支持模式),则返回true。如果Xdebug未加载,或者它正在运行xdebug.mode=off,则返回false。

设置方法

这些方法实现了流畅的接口,必须在主check()方法之前调用。

setLogger(LoggerInterface $logger): self

启用将状态消息输出到外部PSR3日志记录器的功能。所有消息都以DEBUGWARNING日志级别报告。例如(显示级别和消息)

// No restart
DEBUG    Checking MYAPP_ALLOW_XDEBUG
DEBUG    The Xdebug extension is loaded (3.1.1) xdebug.mode=off
DEBUG    No restart (APP_ALLOW_XDEBUG=0) Allowed by xdebug.mode

// Restart overridden
DEBUG    Checking MYAPP_ALLOW_XDEBUG
DEBUG    The Xdebug extension is loaded (3.1.1) xdebug.mode=coverage,debug,develop
DEBUG    No restart (MYAPP_ALLOW_XDEBUG=1)

// Failed restart
DEBUG    Checking MYAPP_ALLOW_XDEBUG
DEBUG    The Xdebug extension is loaded (3.1.0)
WARNING  No restart (Unable to create temp ini file at: ...)

状态消息还可以使用XDEBUG_HANDLER_DEBUG输出。见故障排除

setMainScript(string $script): self

设置重启中要运行的main脚本的路径。仅在更特殊的使用场景中或当argv[0]路径不可访问时需要。支持脚本名--用于标准输入。

setPersistent(): self

使用持久化设置配置重启,这样Xdebug就不会在任何子进程中加载。

如果您的应用程序调用了一个或多个PHP子进程且不需要Xdebug扩展,请使用此方法。这避免了实现特定的子进程策略的开销。

或者,可以使用此方法设置默认的无Xdebug环境,如果子进程需要Xdebug,则可以更改,然后之后恢复

function SubProcessWithXdebug()
{
    $phpConfig = new Composer\XdebugHandler\PhpConfig();

    # Set the environment to the original configuration
    $phpConfig->useOriginal();

    # run the process with Xdebug loaded
    ...

    # Restore Xdebug-free environment
    $phpConfig->usePersistent();
}

进程配置

该库提供了两种策略来调用不加载Xdebug的新PHP进程,使用标准持久设置。请注意,这只在应用程序调用PHP子进程时才重要。

标准设置

仅使用命令行选项从新进程中删除Xdebug。

  • 添加了-n选项到命令行。这告诉PHP不要扫描额外的inis。
  • 使用-c选项将临时ini添加到命令行。

如果新进程调用PHP子进程,Xdebug将加载到该子进程中(除非它实现了xdebug-handler,在这种情况下将会有另一个重启)。

这是重启中使用的默认策略。

持久设置

使用环境变量从新进程中删除Xdebug并将这些设置持久化到任何子进程中。

  • PHP_INI_SCAN_DIR设置为空字符串。这告诉PHP不要扫描额外的inis。
  • PHPRC设置为临时ini。

如果新进程调用PHP子进程,Xdebug将不会加载到该子进程中。

可以通过调用setPersistent()来在重启中使用此策略。

子进程

PhpConfig辅助类使得无论是否重启,都可以轻松调用PHP子进程(带或不带Xdebug加载)。

它的每个方法都返回一个PHP选项数组(用于添加到命令行),并为所需的策略设置环境。内部使用 getRestartSettings() 方法。

  • useOriginal() - Xdebug将被加载到新进程中。
  • useStandard() - Xdebug将不会加载到新进程中 - 请参阅标准设置
  • userPersistent() - Xdebug将不会加载到新进程中 - 请参阅持久设置

如果没有重启,则返回一个空选项数组,并且环境不会被更改。

use Composer\XdebugHandler\PhpConfig;

$config = new PhpConfig;

$options = $config->useOriginal();
# $options:     empty array
# environment:  PHPRC and PHP_INI_SCAN_DIR set to original values

$options = $config->useStandard();
# $options:     [-n, -c, tmpIni]
# environment:  PHPRC and PHP_INI_SCAN_DIR set to original values

$options = $config->usePersistent();
# $options:     empty array
# environment:  PHPRC=tmpIni, PHP_INI_SCAN_DIR=''

故障排除

以下环境设置可用于排查意外行为

  • XDEBUG_HANDLER_DEBUG=1 将状态消息输出到STDERR,如果已定义,则不受任何PSR3日志记录器的影响。每条消息都以前缀xdebug-handler[pid]开头,其中pid是进程标识符。

  • XDEBUG_HANDLER_DEBUG=2 如上所述,但此外还会保存临时ini文件,并在状态消息中报告其位置。

扩展库

API由类及其未标记为@internal的可访问元素定义。主类有两个受保护的方法,可以覆盖以提供附加功能

requiresRestart(bool $default): bool

默认情况下,如果Xdebug被加载并且没有使用xdebug.mode=off运行,进程将重新启动。扩展此方法允许应用程序通过返回布尔值(或等效值)来决定。只有在MYAPP_ALLOW_XDEBUG为空时才会调用它,因此它不会在重启的进程(其中此变量包含内部数据)中调用,或者如果重启已被覆盖。

注意,如果需要,可以使用setMainScript()setPersistent()设置器。

restart(array $command): void

应用程序可以扩展此功能以修改临时ini文件,其位置由tmpIni属性给出。可以在数据的末尾安全地追加新设置,该数据以PHP_EOL终止。

参数$command是一个未转义的命令行参数数组,将用于新进程。

请记住以parent::restart($command)结束。

示例

此示例演示了扩展基本功能两种方法

  • 为了避免启动新进程的开销,如果请求简单的帮助命令,则跳过重启。

  • 应用程序需要写入phar文件,因此如果设置phar.readonly,则将强制重启(无论是否加载Xdebug)并在临时ini文件中更改此值。

use Composer\XdebugHandler\XdebugHandler;
use MyApp\Command;

class MyRestarter extends XdebugHandler
{
    private $required;

    protected function requiresRestart(bool $default): bool
    {
        if (Command::isHelp()) {
            # No need to disable Xdebug for this
            return false;
        }

        $this->required = (bool) ini_get('phar.readonly');
        return $this->required || $default;
    }

    protected function restart(array $command): void
    {
        if ($this->required) {
            # Add required ini setting to tmpIni
            $content = file_get_contents($this->tmpIni);
            $content .= 'phar.readonly=0'.PHP_EOL;
            file_put_contents($this->tmpIni, $content);
        }

        parent::restart($command);
    }
}

示例

tests\App目录包含命令行脚本,这些脚本在各种场景中展示了内部工作方式。请参阅功能测试脚本

许可

composer/xdebug-handler遵循MIT许可证,有关详细信息,请参阅LICENSE文件。