Restarts a process without xdebug.
Restart a CLI process without loading the xdebug extension.
Originally written as part of composer/composer, now extracted and made available as a stand-alone library.
Install the latest version with:
$ composer require composer/xdebug-handler
- PHP 5.3.2 minimum, although functionality is disabled below PHP 5.4.0. Using the latest PHP version is highly recommended.
use Composer\XdebugHandler\XdebugHandler; $xdebug = new XdebugHandler('myapp'); $xdebug->check(); unset($xdebug);
The constructor takes two parameters:
This is used to create distinct environment variables and is upper-cased and prepended to default base values. The above example enables the use of:
MYAPP_ALLOW_XDEBUG=1to override automatic restart and allow xdebug
MYAPP_ORIGINAL_INISto obtain ini file locations in a restarted process
This optional value is added to the restart command-line and is needed to force color output in a piped child process. Only long-options are supported, for example
If the original command-line contains an argument that pattern-matches this value, for example
--colors=never, then $colorOption is ignored.
If the pattern-match ends with =auto, for example
--colors=auto, the argument is replaced by $colorOption. Otherwise it is added at either the end of the command-line, or preceeding a double-dash
A temporary ini file is created from the loaded (and scanned) ini files, with any references to the xdebug extension commented out. Current ini settings are merged, so that settings made on the command-line or by the application are included.
MYAPP_ALLOW_XDEBUGis set with internal data to flag and use in the restart.
-noption is added to the command-line. This tells PHP not to scan for additional inis.
- The temporary ini is added to the command-line with the
- The application is restarted in a new process using
- The application runs and exits.
- The main process exits with the exit code from the restarted process.
If the application does anything with ini files, then functions like
php_ini_scanned_files will not work correctly in a restarted process.
To make the original locations available, they are saved to the environment variable suffixed
_ORIGINAL_INIS. This is a path-separated string comprising the location returned from
php_ini_loaded_file, which could be empty, followed by locations parsed from calling
A static helper method
XdebugHandler::getAllIniFiles is provided to access these values in a single array, regardless of whether the process has been restarted or not.
use Composer\XdebugHandler\XdebugHandler; $files = XdebugHandler::getAllIniFiles(); # $files always exists, it could be an empty string $loadedIni = array_shift($files); $scannedInis = $files;
Other static helper methods provide information about the current process, which may or may not have been restarted:
XdebugHandler::getSkippedVersion- the xdebug version string that was skipped by the restart, or an empty value.
XdebugHandler::getRestartSettings- an array of settings to use with PHP sub-processes, or null.
use Composer\XdebugHandler\XdebugHandler; $version = XdebugHandler::getSkippedVersion(); # $version: '2.6.0' (for example), or an empty string $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) */
Calling a PHP process from a restarted process using the original configuration will result in one of two outcomes:
- xdebug will be loaded in the new process.
- If the new process implements xdebug-handler, it will restart without loading xdebug.
XdebugHandler::getRestartSettings() method provides data that can be used to call a PHP sub-process. For example:
Using standard restart settings.
tmpInito the command-line.
- xdebug will not be loaded, but points 1 and 2 apply to any sub-process.
Using persistent environment variables.
PHP_INI_SCAN_DIRto an empty string if
- xdebug will not be loaded in this or any sub-process.
The PhpConfig class can be used to manage these scenarios.
This helper class provides command-line options and sets up the environment for calling a PHP sub-process. If there was no restart (because it was overriden, or xdebug is not present), an empty options array is returned and the environment is not changed.
use Composer\XdebugHandler\PhpConfig; $config = new PhpConfig; $options = $config->useOriginal(); # $options: empty array # environment: restored $options = $config->useStandard(); # $options: [-n, -c, tmpIni] # environment: restored $options = $config->usePersistent(); # $options: empty array # environment: sets PHPRC, PHP_INI_SCAN_DIR (if needed)
setLogger method enables the output of status messages to an external PSR3 logger.
use Composer\XdebugHandler\XdebugHandler; $xdebug = new XdebugHandler('myapp'); // Provide a PSR3 logger $xdebug->setLogger($myLogger);
All messages are reported with either
WARNING log levels. For example (showing the level and message):
// Restart overridden DEBUG Checking MYAPP_ALLOW_XDEBUG DEBUG The xdebug extension is loaded (2.5.0) DEBUG No restart (MYAPP_ALLOW_XDEBUG=1) // Failed restart DEBUG Checking MYAPP_ALLOW_XDEBUG DEBUG The xdebug extension is loaded (2.5.0) WARNING No restart (Unable to create temporary ini file)
Status messages can also be output with
XDEBUG_HANDLER_DEBUG. See the Debugging section, below.
The process will not be restarted if the
argv location of the main script is inaccessible. This is only likely in more esoteric use-cases and can be fixed by using the
// Save the full path to the invoked script $mainScript = realpath($_SERVER['argv']); ... use Composer\XdebugHandler\XdebugHandler; $xdebug = new XdebugHandler('myapp'); $xdebug->setMainScript($mainScript); // The script name "--" is also supported (for standard input)
The API is defined by classes and their accessible elements that are not annotated as @internal. The main class has two protected methods that can be overriden to provide additional functionality:
By default the process will restart if xdebug is loaded. Overriding this allows an application to decide. This method is only called if
MYAPP_ALLOW_XDEBUG is empty.
An application can hook into this to access the temporary ini file, its location given in the
The following environment settings can be used to troubleshoot unexpected behavior:
XDEBUG_HANDLER_DEBUG=1Outputs status messages to standard output, irrespective of any PSR3 logger. Each message is prefixed
xdebug-handler[pid], where pid is the process identifier.
XDEBUG_HANDLER_DEBUG=2As above, but additionally saves the temporary ini file and reports its location in a status message.
composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details.