With Sail, you can start debugging your Laravel application in less than 5 minutes!
But, first lets understand the use cases/ modes:
- Debugging - Stop a script mid execution to inspect variables
- Profiling - Look at slow bottlenecks in a request
- Coverage - Monitor how much code is tested
What will we learn? Link to heading
- Why modern Xdebug is so easy
- How does Sail do it?
- The Xdebug settings
- Using the debugger in the browser
- Using the profiler
- Using code coverage for tests
xdebug_info()
Why modern Xdebug is so easy Link to heading
The current version, Xdebug 3, has one key difference that makes using it easy:
export XDEBUG_CONFIG="client_host=192.168.42.34 log=/tmp/xdebug.log"
Instead of using php.ini
files, you can configure Xdebug using environment variables.
This means you can enable the debugger, use it for a few requests, then disable it. All without delving into the server internals, or re-building instances.
How does Sail do it? Link to heading
Lets have a look at laravel/sail on GitHub to see how its taking advantage of this new configuration.
First, we see a Dockerfile
for each supported PHP version. Looking inside runtimes/8.2/Dockerfile
, we find:
apt-get install php8.2-xdebug
It is following the instructions provided by Xdebug for installation on a Ubuntu distribution.
Next, we see the docker-compose.stub
has two environment variables:
environment:
XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
These keys and values are ’nearly’ identical to the ones Xdebug uses!
And that’s it! Docker Compose passes these environment variables to the Ubuntu container, and Xdebug uses them.
Well thats not completely it, there’s one extra thing…
In artisan
, theres a command for sail debug ...
to activate the debugger:
ARGS+=(exec -u sail -e XDEBUG_SESSION=1)
So, again it is following the instructions provided by Xdebug for activating the debugger in the command line.
The Xdebug settings Link to heading
Only a select set of settings can be set through this XDEBUG_CONFIG
variable. Some more useful settings are:
cli_color=0
client_host=localhost
client_port=9003
idekey=*complex*
log=/tmp/xdebug.log
log_level=7
mode=develop
output_dir=/tmp
profiler_output_name=cachegrind.out.%p
mode
is set using the XDEBUG_MODE
and used like: XDEBUG_MODE=develop,debug
To use each setting, you can add them like this:
XDEBUG_CONFIG="client_host=192.168.42.34 log=/tmp/xdebug.log"
You can find documentation for all of the settings here: https://xdebug.org/docs/all_settings
Using the debugger in the browser Link to heading
The debugger is the most documented usage of Xdebug, so I wont write too much. You can see:
Or, if you use macOS, PHPStorm and Chrome, you can use my setup:
- Add
SAIL_XDEBUG_MODE=develop,debug
to your.env
- Run
./vendor/bin/sail up
- On the PHPStorm toolbar, toggle
Start Listening for PHP Debug Connections
- Again, on the toolbar, toggle
Break at first line in PHP scripts
- Install
Chrome Xdebug helper
extension - Visit http://localhost, with Chrome extension set to Debug
Using the profiler Link to heading
The profiler allows you to visualise bottlenecks in your PHP code execution, for example slow running functions or high memory usage.
So, lets set it up:
First, update your .env
variables:
SAIL_XDEBUG_MODE=profile
SAIL_XDEBUG_CONFIG="client_host=host.docker.internal output_dir=/var/www/html/storage/app profiler_output_name=cachegrind.out.%R.%u"
profiler_output_name
. See my StackOverflow question for more info. But simply, Clockwork required 1 file per request.Next, composer require itsgoingd/clockwork --dev
, and visit http://localhost/clockwork
to start listening for requests to profile!
Finally, stop/ start Sail and start making web requests to your application!
Using Clockwork, you can view the call graph for your request.
Webgrind Link to heading
If you want a quick’n’dirty way to visualise your profiles, I use Webgrind (Because the popular kcachegrind doesnt work on macOS).
Using the configuration above, you can run:
docker run --rm -v /path/to/project/storage/app:/tmp -p 2000:80 jokkedk/webgrind:latest
Then open http://localhost
in your browser load the profile and inspect it!
Using code coverage for tests Link to heading
The code coverage allows you to output the amount of code executed during a request. Its useful to see the % code coverage of your test suite.
This is well documented over at Laravel News.
Or, a tldr;
- Set
SAIL_XDEBUG_MODE=coverage
- Run
php artisan test --coverage
- To generate a HTML file report, edit
phpunit.xml
:
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</include>
<report>
<html outputDirectory="storage/app"/>
</report>
</coverage>
xdebug_info() Link to heading
With Xdebug 3, we can use xdebug_info()
to check what config Xdebug is using.
If we set SAIL_XDEBUG_MODE=debug
in our .env
file and stop/ start Sail, you should see a page like the phpinfo()
output.
This is useful for checking your configuration has loaded correctly.
Conclusion Link to heading
Because Xdebug is way easier to use than it used to be, and the debugger/ profiler are invaluable tools for local development, I think this post adds a lot of value on top of the existing documentation.
You may be like me, having spent hours in StackOverflow trying to resolve issues with Xdebug and Chrome/ PHPStorm/ Docker.
But, after reading this article, you can see just how easy it is and start improving your local dev workflow, as well as improving performance bottlenecks before you get to production.
Outro Link to heading
This blog is to help me remember what I have done, hopefully teach others and get feedback and learn from others.
Please let me know if you have tried this, or have any different thoughts on Twitter @natenatters.