Here, I’m going to talk about configuring XDebug with PHPStorm and Docker.
ℹ️ Important note: I will not talk about using it in an HTTP context. I have struggled so much in the past and never succeeded in configuring this, and I will probably never do it anyway.
I’m only using it when testing, with PHPUnit or Behat, and that’s perfect: it forces me to write more tests.
Having a working Docker environment
Apparently, XDebug is not installed at all with Laravel Sail. In order to include it, you have to modify the Dockerfile, edit docker-compose.yml and rebuild the containers. Here is how I did. I copied the Docker configuration Laravel Sail uses in a more convenient place. XDEBUGCONFIG - This variable allows to define some Xdebug configurations. The 'remote host' is the private ip of your host machine (the one your PHPStorm is running). The 'remoteport' is the port that PHPStorm will be listening for incoming Xdebug connections. These two settings allow PHPStorm and Xdebug to communicate. It wont work without this. I have docker installed on my Linux host and raised a container with php-fpm and xdebug. Phpstorm is installed on Windows server. The project is hoisted through gitlab. Can you please tell me how to set up debugging via xdebug in such a bundle? Laravel Homestead is great, it supports multiple php versions, xDebug, MySQL and allows the user to install any other required software straight into the virtual machine. Right now I may suggest: 1) Change Xdebug port to be 9001 (just in case) in both php.ini and PhpStorm. 2) Make sure that you have 'phone handle' icon ON (so IDE is listening for incoming Xdebug connections). Ensure that PhpStorm is the one that listens on that port (e.g. Sudo lsof -nP -iTCP -sTCP:LISTEN` or alike).
First of all, if we talk about Docker, you may refer to the series of blog posts I wrote about Docker, it might help you.
I will now consider you have a working PHP + Docker environment.
I also consider you already installed the Docker plugin for your PHPStorm IDE.
Make sure XDebug is available
Of course now you have a working Docker setup, but remember that XDebug must be present.
I usually install it in my Docker images by adding a RUN
statement with (echo ' | pecl install xdebug)
.
This echo
thing is a trick to force pecl
to execute in a “non-interactive” mode, in order to let the Docker image be built automatically with no user interaction (which is not possible).
If you have PHP 7.2+, you can even make your debug-based test scripts cross-compatible with any platform thanks to extension loading by name.TL;DR: it means that you can do php -dzend_extension=xdebug
instead of php -dzend_extension=xdebug.so
for UNIX and php -dzend_extension=xdebug.dll
for Windows. Yeah, it’s just about removing the extension.
To know whether XDebug is available, run php -dzend_extension=xdebug -i | grep xdebug
.
If all XDebug options are displayed with their default/configured values, it works!
Start configuring!
Okay, let’s see ALL the steps that I go through to set this up.
First, the PHP interpreter
Let’s consider we have a php
container running, configured in our docker-compose.yaml
file.
PHPStorm will need a PHP interpreter.
For this, go to the File | Settings | Languages & Frameworks | PHP
menu.
You should see something like this:
Now, you need to click on the [...]
button at the right of the CLI Interpreter
section in order to create/use a PHP interpreter.
You might have an existing PHP interpreter, but for the sake of the example, I’ll show you how to configure your PHP Docker container.
Add a new “Remote Interpreter” by clicking on the big +
sign:
You should configure the remote interpreter to use Docker Compose
and have something similar to this:
If it comes that you have the Server
section to be empty, click on New
and you may see something like this:
Note: I am using Windows, and I deliberately checked the Expose daemon on tcp://localhost:2375 without TLS
checkbox in Docker For Windows configuration.I may update this post in the future for linux-specific config, so check out your docker machine in the first place to see if it can be linked to PHPStorm instead of using the legacy daemon tcp socket.
Here is my final configuration:
Some notes:
- You should decide on whether you want PHPStorm to use
docker-compose run --rm php
ordocker-compose exec php
.run
guarantees an isolated container, but is slower because it needs to start the container first.exec
is faster because it connects to a running container, but may have concurrence issues, even though it’s rare (feel free to share experience on that!). - You can add Environment Variables for each interpreter. That’s nice if you want a “test-optimized” or a “profiling-optimized” one, etc.
- Note the
Debugger extension
field: if you writexdebug
(orxdebug.so
orxdebug.dll
for PHP<=7.1), PHPStorm will automatically append-dzend_extension=xdebug
when running a script in “Debug Mode”.
Phew! Now we have PHP, let’s install PHPUnit!
PHPUnit
You may have noticed that I’m a big Symfony fan, so we will take the example of a Symfony project here.
First, I do composer require phpunit
. This will install the symfony/test-pack
package, which is a package that requires a few other packages, with in particular the symfony/phpunit-bridge
package.
The Symfony PHPUnit Bridge component comes with a modified version of PHPUnit (TL;DR: it’s a wrapper around PHPUnit) that will allow you to not require PHPUnit in your composer.json
file. This might save some dependencies issues, because PHPUnit and your project might depend on same packages with different versions, and you don’t want that. Apart from that, the component provides some other nice features you may check on the docs.
Apart this “dependencies conflicts” theory, the PHPUnit team decided to use PHP-Scoper for their PHAR version, so if you use the phpunit.phar
file, you will not have any conflict either, and that’s okay.
The good thing about this is that requiring it like this on a modern Symfony 4/5 project will install the PHPUnit Bridge Flex recipe that commes with a nice bin/phpunit
script.
Very convenient for command-line, but don’t use it with PHPStorm (I will talk about this later).
Right after your composer require phpunit
, execute bin/phpunit --version
.
The wrapper provided by Symfony will install PHPUnit, find a good version for your system.
You can still override the version in the phpunit.xml.dist
file created by the Flex recipe. I personally always update.
By default (as of the time I write this post), PHPUnit is installed via a big composer create-project
command (you can find it here) into your bin/.phpunit/phpunit-{version}/
directory.
This point is important, because we will configure the PHPUnit “Run configuration” in PHPStorm by using this specific configuration.
Now! Comes the moment where we move back to PHPStorm!
First, click on the Add Configuration...
button on the top-right section of your PHPStorm screen:
Then, add a PHPUnit
configuration:
An empty PHPUnit configuration never works.
PHPStorm needs many things for it to work:
- A working PHP Interpreter
- A way to execute PHPUnit (autoloader, include path, executable…)
- An optional configuration file (but we must set it anyway, else PHPStorm’s PHPUnit process will not use the
phpunit.xml.dist
file at all)
So, to make it work, configure PHPUnit:
Add a new PHPUnit configuration with a Remote Interpreter:
Select the remote interpreter you created with your Docker configuration.
Then, we will tell PHPStorm to look for the PHPUnit executable.
When we ran bin/phpunit --version
, the bridge installed PHPUnit in bin/.phpunit/phpunit-{version}
, remember? We will pick the executable from there.Important: remember that the script path will be inside the Docker container, so be careful about paths.
Also remember to fill the Default configuration file
field, else PHPUnit will not use any config.
Note: You might have slight differences in paths and versions depending on your Docker and PHPUnit configuration.
After that: PHPUnit is configured!
And for XDebug, we installed it.
Run a PHPUnit script in Debug mode with step-by-step debugging
To run in Debug mode, you have the little bug icon next to the “Run” button in your “Run configuration” top bar:
Click on it, and see if your project is tested!
Now, we’ll do step-by-step debugging, thanks to XDebug and PHPStorm’s integration.
Find some piece of code you want to test, and add a breakpoint. To do so, you can left-click in the left gutter of the line you want to stop by when running the test, or you can also place the cursor on the line and press Ctrl+F8
(Windows keymap).
Now, DEBUG!
The test will execute and PHPStorm will open a brand new tab so you can debug everything: stack trace, variables state, etc.
You can now start your step-by-step debugging, thanks to these buttons:
These buttons allow you to execute current line and go to next instruction, step into the function/method call, step out of the current function, etc.
Have fun doing better debugging than dump($var);exit;
!
Late notes:
Why do I choose to not use bin/phpunit
?
Well, because it simply does not run with PHPStorm.
The reason might be that as it is a wrapper around PHPUnit, Symfony adds features to it (or removes some), especially the one that installs PHPUnit in the first place.
Then, PHPStorm needs to execute this script before finishing the config, because it needs to know which version of PHPUnit is installed (either for auto-completion, autoload, or maybe PHPUnit-specific stuff I am not aware of).
The wrapper does not return the same contents than the native PHPUnit script, so PHPStorm will consider it either not working or incompatible.
This is why I use the native PHPUnit script that is installed by executing bin/phpunit --version
Created at 2020-10-10Updated at 2020-10-11Category Docker Tag Resource / Docker / PHP / PhpStorm / PhpUnit / Linux
I have recently configured my windows 10 laptop with an additional SSD, so I could experiment with Linux. I have already installed Pop!_OS Git, PhpStorm and Docker. I haven’t installed PHP or Composer locally. Next I want to learn how to use this new environment. This is what I have found out so far.
Start with a Project
One of my favorite projects is the Gilded Rose Kata. I can clone that from github as follows:
Create docker-compose.yml
It is possible to run PHP cli without a docker-compose file, I have found it is easier to set up PhpStorm using this intermediate step.
PhpStorm has several preconfigured Docker containers, source:
They can be used as follows:
Php 7.3 CLI and XDebug 2.7
docker-compose.yml
The above will work for Linux, for Windows and MacOS the XDEBUG_CONFIG:
will need the changed as follows:
Windows and MacOS
Windows and MacOS replace with XDEBUG_CONFIG:host.docker.internal
, which will automatically resolve to the internal address of the host Docker is running on.
MacOS with local Homebrew php-fpm
If you use a local Homebrew php-fpm installation, port 9000 (which is the default debugging port) may become occupied. PhpStorm will remain silent on starting listening for incoming connections. If this is the case, in the Settings | Languages & Frameworks | PHP | Debug, set the Debug port to 9001, and use the following configuration line instead.
Apache, PHP 7.3, XDebug 2.7 and MySQL
For information this is the LAMP version (based on the phpstorm-workshop).
docker-compose.yml
Install dependencies using composer
To keep things simple the composer Docker container can be used to install the dependencies.
This is the script recommended on the docker hub composer page to avoid filesystem permissions problems
By default, Composer runs as root inside the container. This can lead to permission issues on your host filesystem. You can work around this by running the container with a different user:
On windows change $PWD
for the full path to the project (note: forward slash / as separator), remove the line end and run the command as one line:
Alternatively, more complex projects will need specific PHP extensions to be installed, which are not included in the Composer Docker container. The following method could be used to install Composer, inside the container and install the dependencies.
- Access bash in the php-cli container:
docker-compose run --rm php-cli /bin/bash
- Install Composer, by following the download instructions for Linux
- Still, inside the container, install dependencies:
php composer.phar install
- Exit the container
exit
Note: In Linux, using the second method Composer will create the vendor folder as root!
The permissions can be changed using chown:
Further information
There is a detailed description about running Docker containers as current host user.
The official documentation on Docker run and docker-compose cli reference.
Configure PhpStorm
Now the project has been cloned from GitHub and the dependencies have been installed. PhpStorm can be setup to use Docker. Thanks to Gary Hockin’s excellent YouTube video Running PHPUnit Tests in PhpStorm with Docker, the setup process can be easily replicated.
There is a four stage process:
- Configure PhpStorm to use Docker
- Configure the remote interpreter
- Configure PhpUnit
- Create Test runner
1. Configure PhpStorm to use Docker
- Settings (Ctrl + Alt + S)
- Search for Docker
- Under Build, Execution, Deployment
- Click + to add
- Select Unix socket
- Confirm connection was successful
2. Configure the default CLI interpreter
- Settings (Ctrl + Alt + S)
- Search for CLI interpreter
- Under Language & Frameworks > PHP
- Click the ellipse button next to CLI Interpreter
- Click +
- Select From Docker, Vagrant…
- Choose Docker Compose
- Choose the Service from the drop down list (e.g. php-cli)
- Select OK
- Change the name e.g. Docker PHP
- Apply and OK
- Check the mapping
- e.g. for a web project <Project root>→/var/www/html
- e.g. for an app project <Project root>→/app
3. Configure PhpUnit
- Settings (Ctrl + Alt + S)
- Search for Test Frameworks
- Under Language & Frameworks > PHP
- Click +
- Select PhpUnit from remote interpreter
- Choose the interpreter created above, e.g. Docker PHP
- Confirm the path mappings, as above <Project root>→/app
- Input the script path based on the mapping inside the container e.g. /app/vendor/autoload.php
- Under Test runner, tick Default configuration script, type in the path, in the docker container. e.g. /app/phpunit.xml
4. Create the test runner
- Click Edit Configuration (next to run test button)
- Click + to add
- Select PHPUnit
- Under Test Runner choose Defined in the configuration file
- Name - e.g. Docker PHPUnit
- Click Play to run all the tests!
What about configuring xDebug?
Phpstorm Docker Compose
Thanks to this setup, xDebug has been automatically configured! It will use the default PHP Interpreter, which was configured in step 2. A breakpoint can be set in the app or tests can be run with coverage :)
Enjoy the kata!
Phpstorm Xdebug Ssh
Edit: Added details on running commands on MacOS and Windows and small tweaks.