Restart A CLI Process without Loading The Xdebug Extension


Restart a CLI process without loading the Xdebug extension, unless xdebug.mode=off.

Originally written as part of composer/composer, now extracted and made available as a stand-alone library.

Version 3

Removed support for legacy PHP versions and added type declarations.

Long term support for version 2 (PHP 5.3.2 - 7.2.4) follows Composer 2.2 LTS policy.


Install the latest version with:

$ composer require composer/xdebug-handler


  • PHP 7.2.5 minimum, although using the latest PHP version is highly recommended.

Basic Usage

use Composer\XdebugHandler\XdebugHandler;

$xdebug = new XdebugHandler('myapp');

The constructor takes a single parameter, $envPrefix, which is upper-cased and prepended to default base values to create two distinct environment variables. The above example enables the use of:

  • MYAPP_ALLOW_XDEBUG=1 to override automatic restart and allow Xdebug
  • MYAPP_ORIGINAL_INIS to obtain ini file locations in a restarted process

Advanced Usage

How it works

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 most ini settings made on the command-line or by the application are included (see Limitations)

  • MYAPP_ALLOW_XDEBUG is set with internal data to flag and use in the restart.
  • The command-line and environment are configured for the restart.
  • The application is restarted in a new process.
    • The restart settings are stored in the environment.
    • MYAPP_ALLOW_XDEBUG is unset.
    • The application runs and exits.
  • The main process exits with the exit code from the restarted process.

Signal handling

Asynchronous signal handling is automatically enabled if the pcntl extension is loaded. SIGINT is set to SIG_IGN in the parent process and restored to SIG_DFL in the restarted process (if no other handler has been set).

From PHP 7.4 on Windows, CTRL+C and CTRL+BREAK handling is automatically enabled in the restarted process and ignored in the parent process.


There are a few things to be aware of when running inside a restarted process.

  • Extensions set on the command-line will not be loaded.
  • Ini file locations will be reported as per the restart - see getAllIniFiles().
  • Php sub-processes may be loaded with Xdebug enabled - see Process configuration.

Helper methods

These static methods provide information from the current process, regardless of whether it has been restarted or not.

getAllIniFiles(): array

Returns an array of the original ini file locations. Use this instead of calling php_ini_loaded_file and php_ini_scanned_files, which will report the wrong values in a restarted process.

use Composer\XdebugHandler\XdebugHandler;

$files = XdebugHandler::getAllIniFiles();

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

These locations are also available in the MYAPP_ORIGINAL_INIS environment variable. 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 php_ini_scanned_files.

getRestartSettings(): ?array

Returns an array of settings that can be used with PHP sub-processes, or null if the process was not restarted.

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

Returns the Xdebug version string that was skipped by the restart, or an empty string if there was no restart (or Xdebug is still loaded, perhaps by an extending class restarting for a reason other than removing Xdebug).

use Composer\XdebugHandler\XdebugHandler;

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

isXdebugActive(): bool

Returns true if Xdebug is loaded and is running in an active mode (if it supports modes). Returns false if Xdebug is not loaded, or it is running with xdebug.mode=off.

Setter methods

These methods implement a fluent interface and must be called before the main check() method.

setLogger(LoggerInterface $logger): self

Enables the output of status messages to an external PSR3 logger. All messages are reported with either DEBUG or WARNING log levels. For example (showing the level and message):

// No restart
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    The Xdebug extension is loaded (3.1.1) xdebug.mode=coverage,debug,develop

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

Status messages can also be output with XDEBUG_HANDLER_DEBUG. See Troubleshooting.

setMainScript(string $script): self

Sets the location of the main script to run in the restart. This is only needed in more esoteric use-cases, or if the argv[0] location is inaccessible. The script name -- is supported for standard input.

setPersistent(): self

Configures the restart using persistent settings, so that Xdebug is not loaded in any sub-process.

Use this method if your application invokes one or more PHP sub-process and the Xdebug extension is not needed. This avoids the overhead of implementing specific sub-process strategies.

Alternatively, this method can be used to set up a default Xdebug-free environment which can be changed if a sub-process requires Xdebug, then restored afterwards:

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

    # Set the environment to the original configuration

    # run the process with Xdebug loaded

    # Restore Xdebug-free environment

Process configuration

The library offers two strategies to invoke a new PHP process without loading Xdebug, using either standard or persistent settings. Note that this is only important if the application calls a PHP sub-process.

Standard settings

Uses command-line options to remove Xdebug from the new process only.

  • The -n option 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 -c option.

If the new process calls a PHP sub-process, Xdebug will be loaded in that sub-process (unless it implements xdebug-handler, in which case there will be another restart).

This is the default strategy used in the restart.

Persistent settings

Uses environment variables to remove Xdebug from the new process and persist these settings to any sub-process.

  • PHP_INI_SCAN_DIR is set to an empty string. This tells PHP not to scan for additional inis.
  • PHPRC is set to the temporary ini.

If the new process calls a PHP sub-process, Xdebug will not be loaded in that sub-process.

This strategy can be used in the restart by calling setPersistent().


The PhpConfig helper class makes it easy to invoke a PHP sub-process (with or without Xdebug loaded), regardless of whether there has been a restart.

Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The getRestartSettings() method is used internally.

  • useOriginal() - Xdebug will be loaded in the new process.
  • useStandard() - Xdebug will not be loaded in the new process - see standard settings.
  • userPersistent() - Xdebug will not be loaded in the new process - see persistent settings

If there was no restart, 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:  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=''


The following environment settings can be used to troubleshoot unexpected behavior:

XDEBUG_HANDLER_DEBUG=1 Outputs status messages to STDERR, if it is defined, irrespective of any PSR3 logger. Each message is prefixed xdebug-handler[pid], where pid is the process identifier.

XDEBUG_HANDLER_DEBUG=2 As above, but additionally saves the temporary ini file and reports its location in a status message.

Extending the library

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 overridden to provide additional functionality:

requiresRestart(bool $default): bool

By default the process will restart if Xdebug is loaded and not running with xdebug.mode=off. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if MYAPP_ALLOW_XDEBUG is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.

Note that the setMainScript() and setPersistent() setters can be used here, if required.

restart(array $command): void

An application can extend this to modify the temporary ini file, its location given in the tmpIni property. New settings can be safely appended to the end of the data, which is PHP_EOL terminated.

The $command parameter is an array of unescaped command-line arguments that will be used for the new process.

Remember to finish with parent::restart($command).


This example demonstrates two ways to extend basic functionality:

To avoid the overhead of spinning up a new process, the restart is skipped if a simple help command is requested.

The application needs write-access to phar files, so it will force a restart if phar.readonly is set (regardless of whether Xdebug is loaded) and change this value in the temporary ini file.

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);


Download Details:

Author: Composer
Source Code: 
License: MIT license

#php #performance #xdebug #restart 

Restart A CLI Process without Loading The Xdebug Extension

Webgrind: Xdebug Profiling Web Frontend in PHP


Webgrind is an Xdebug profiling web frontend in PHP. It implements a subset of the features of kcachegrind and installs in seconds and works on all platforms. For quick'n'dirty optimizations it does the job. Here's a screenshot showing the output from profiling:


  • Super simple, cross platform installation - obviously :)
  • Track time spent in functions by self cost or inclusive cost. Inclusive cost is time inside function + calls to other functions.
  • See if time is spent in internal or user functions.
  • See where any function was called from and which functions it calls.
  • Generate a call graph using

Suggestions for improvements and new features are more than welcome - this is just a start.


  1. Download webgrind
  2. Unzip package to favourite path accessible by webserver.
  3. Load webgrind in browser and start profiling

Alternatively, on PHP 5.4+ run the application using the PHP built-in server with the command composer serve or php -S index.php if you are not using Composer.

For faster preprocessing, give write access to the bin subdirectory, or compile manually:

  • Linux / Mac OS X: execute make in the unzipped folder (requires GCC or Clang.)
  • Windows: execute nmake -f NMakeFile in the unzipped folder (requires Visual Studio 2015 or higher.)

See the Installation Wiki page for more.

Use with Docker

Instead of uploading webgrind to a web server or starting a local one, you can use the official Docker image to quickly inspect existing xDebug profiling files. To use the Docker image, run the following command with /path/to/xdebug/files replaced by the actual path of your profiling files.

docker run --rm -v /path/to/xdebug/files:/tmp -p 80:80 jokkedk/webgrind:latest

Now open http://localhost in your browser. After using webgrind you can stop the Docker container by pressing CTRL / Strg + C.

To use the built-in file viewer, mount the appropriate files under /host in the container.


Webgrind is written by Joakim Nygård and Jacob Oettinger. It would not have been possible without the great tool that Xdebug is thanks to Derick Rethans.

Current maintainer is Micah Ng.

Download Details:

Author: jokkedk
Source Code: 
License: View license

#php #xdebug #debugging #tool 

Webgrind: Xdebug Profiling Web Frontend in PHP
Veronica  Roob

Veronica Roob


Xdebug: Step Debugger and Debugging Aid for PHP


Xdebug is a debugging tool for PHP. It provides step-debugging and a whole range of development helpers, such as stack traces, a code profiler, features to dump the full execution of your script to a file, and more.

Repography logo / Recent activity

Timeline graph Pull request status graph Trending topics Top contributors


Xdebug requires a supported version of PHP. For installation it requires the pecl tool (available through the php-pear package), unless your Linux distribution has an Xdebug package (php-xdebug).


On most Linux distributions you can install Xdebug through its package manager. You can also compile from source with the pecl tool through pecl install xdebug. The latter also works for MacOS as long as PHP is installed with Homebrew.

On Windows, you need to download a binary. Use the Wizard.

Unless you have installed Xdebug with a package manager on Linux, you also need to add the following line to your php.ini file, or create a new Xdebug specific ini file xdebug.ini in the conf.d directory. In either case, it needs the following line added:


For more extensive installation instructions, see the documentation at


Most features in Xdebug have to be opted in into. Each feature has a specific opt-in. For example to use the step debugger you need to set xdebug.remote_enable=1 in your configuration file. The step debugger requires an IDE (client), of which there are many available.

The documentation has instructions for each of Xdebug's features: and a full list of settings is also available there.


Xdebug is written in C, and extensive knowledge of PHP's internals is necessary to be able to contribute. Contributing guidance is available separately.

Before you begin to contribute, please reach out first. Either through email (address at the bottom), an issue in the issue tracker or preferably through IRC on Freenode's #xdebug channel.


If you are familiar with compiling PHP extension from source, have a local checkout of Xdebug's GitHub repository, and have compiled Xdebug in that directory following the instructions under installation you can run Xdebug's tests by running:

php run-xdebug-tests.php

The test framework requires that the PHP binary on the path has Xdebug loaded, with remote debugging enabled through xdebug.mode=debug. It is possible to skip remote debugging tests by exporting the SKIP_DBGP_TESTS=1 environment variable.

The SKIP_UNPARALLEL_TESTS=1 can be used to skip tests that can not run in parallel environments, and the SKIP_SLOW_TESTS=1 environment variable to skip slow tests. The OPCACHE environment variable can either be yes or no and controls whether the test framework enables or disables OpCache.


Xdebug is released under The Xdebug License, which is based on The PHP License. It is an Open Source license (though not explicitly endorsed by the Open Source Initiative).

Further Reading

Xdebug has extensive documentation on its website. There are over a hundred settings and many functions documented. Please have a look through the wealth of information that Xdebug can provide to make your every day development with PHP easier.


For questions regarding Xdebug, please use StackOverflow, and tag your question with xdebug.

You can also find ad-hoc and sporadic support on IRC: freenode/#xdebug. You can do that with your favourite client, or by using their webchat.

If you think that you encountered a bug, please file a detailed bug report at You are required to create an account, this is so that you can be contacted for additional information and to keep out spam.

Derick Rethans —

Author: xdebug
Source Code:
License: View license


Xdebug: Step Debugger and Debugging Aid for PHP
Nigel  Uys

Nigel Uys


Laravel 8.0 Sail + XDebug + PHPStorm

Laravel Sail has really been awesome in helping with the most crucial development setup decisions. It doesn’t stop there, if you need to customize it further you can too!


Installing sail is really a joy, and out of the box, you get for free the most important parts of the docker-compose.yml file. Check out the  official guide and skip ahead or follow along here.

To install sail into an ongoing project, or a new project without using the build script, you can install it with composer.

$ composer require laravel/sail --dev

Next, add the alias to your bashrc or zshrc file to use the sail command in your project folder. Open your rc file and add the following line, after which remember to source the file.

alias sail="bash vendor/bin/sail"

Now, run the install script.

$ php artisan sail:install

After deciding which of the services you want to install, via the CLI prompt, you can now spin up the containers.

$ sail up -d

#xdebug #laravel #docker #phpstorm

Laravel 8.0 Sail + XDebug + PHPStorm
Nigel  Uys

Nigel Uys


Xdebug Laravel Sail project in VS Code

If you are not a newcomer to PHP, you may hear about Xdebug — A PHP extension that gives you the power of debugging and profiling capabilities.

Maybe… you are the fans of dd()var_dump(), or print_r(), but Xdebug gives you more powerful tools with IDE to capture the nasty bug! (and perhaps save you from the sleepless night)

I assume you have started your project with Laravel Sail. If not, you can read  Kickstart your Laravel Web App using Laravel Sail.

Sadly, you cannot choose to add the Xdebug package directly as you saw from the  official documentation. There is a debate about Xdebug support in the laravel/sail repo; you may take a look if you are interested.

However, it can’t stop you from customizing YOUR Docker container! Let us step-by-step to add Xdebug to our project.

🐳 Edit Docker Configuration

1. Make sure you sail up -d before we start.

2. Execute sail artisan sail:publish to publish the configuration files.

You will see the docker folder and docker-compose.yml file.

3. You can sail down now when we are editing the docker config files.

4. Add Line 10 & Line 11 for the Xdebug on/off switch(XDEBUG) and port number(XDEBUG_PORT) in docker-compose.yml. Your .env file should also set APP_DEBUG as true.

#xdebug #vscode #laravel #laravel-sail

Xdebug Laravel Sail project in VS Code

Debug with VSCode, Xdebug and Docker on Windows

Each dev environment has its own Xdebug config. At Naept, we adopted docker-compose a few months ago. This article presents a way to configure the Docker container and VSCode to enable Xdebug, all that in Windows.

This tutorial assumes that Docker for Windows is up and running on your computer, as well as VSCode. We are going to make a simple PHP project together, that we are going to see in action in VSCode.

Let’s agree on some vocabulary

Before we start, here are some of the terms used in this article.


It means Integrated Development Environment. It refers to software that is made to write code. We could well write code in the windows notepad, but IDE brings a lot of nice features, like correcting, indenting, auto-completing… And integrated visual interfaces for databases, versioning…


It means PHP Extensions Community Library. PECL is a repository for PHP extensions, providing a directory of all known extensions and hosting facilities for downloading and development of PHP extensions.

#xdebug #docker #php #debugging #vscode

Debug with VSCode, Xdebug and Docker on Windows

Setup Wordpress Debug Environment With Docker and Xdebug

It’s a common practice to debug PHP using Xdebug. Xdebug is an extension for PHP to assist with debugging and development.

In this article, I’m going to introduce a more convenient way to quickly set up development environment with PHPStorm, Docker, Docker compose and Xdebug. The source code for docker compose configs are available in the Github:

First of all, suppose we have installed Docker and Docker compose in a Linux-like OS, and installed a Wordpress site in production. Then, what we need to do is to setup a development environment for that site so that we can customize plugins or what else. This post will help you learn how to:

  • Use Docker compose to mange docker containers.
  • Export production db to dev Mysql docker container.
  • Integrate Xdebug plugin with docker container as well as PHPStorm.
  • How to initialize MySQL container with sql script file.

docker-compose.yml for container management


version: "3"



    image: mysql:5.7

    container_name: mysqldb


      - "3306:3306"






      - ./configs/db/:/docker-entrypoint-initdb.d ## mysql will execute the initial sql script under the mount point one by one

      - db-data:/var/lib/mysql




    container_name: wordpress-app

 - "80:80"

      - "443:443"

    restart: always


      XDEBUG_CONFIG: "remote_host=host.docker.internal" #This config works for MacOS, otherwise should be ip address of the host machine because docker container cannot find the host by localhost.


      - ../local-wordpress:/var/www/html ## mount your local wordpress site here

      - /tmp/wp-errors.log:/tmp/wp-errors.log


      - mysql



#php #docker #mysql #wordpress #docker compose #phpstorm #xdebug

Setup Wordpress Debug Environment With Docker and Xdebug