by Shadi Sharaf
# Introduction
"Debugging is the process of finding the root cause of, and possible fixes for a bug."
aka: writing code
aka: fixing code
80% of time
20% of time
🤖 20% of time
😫 80% of time
# Introduction
# Introduction
aka
# Introduction
aka
# Introduction
or my favorite one
# Introduction
or my favorite one
# Introduction
# Introduction
"Stepping (step debugging) refers to the debugging method of executing code one instruction or line at a time.
The programmer may examine the state of the program, machine, and related data before and after execution of a particular line of code."
# Introduction
# Introduction
# Introduction
# Introduction
# Introduction
Xdebug is a PHP extension for debugging and profiling, it's one of a few debugging extensions for PHP, but is certainly the most popular!
# Introduction
PHP Extension
- Install
- Configure
- Verify
Triggers
- Browser extension
- Environment variables
Editor
- Extension
- Configuration
# Setup
# Install via PECL
sudo pecl install xdebug
# Enable the extension
sudo -E docker-php-ext-enable xdebug
# wp-env also has an xdebug flag
$ wp-env start --xdebug
🔗 Official guide: https://xdebug.org/docs/install
# Setup
# Configure xdebug.ini
xdebug.mode=debug
xdebug.start_with_request=trigger
xdebug.client_host={EDITOR_IP_ADDRESS}
xdebug.client_port={EDITOR_XDEBUG_PORT}
🔗 Official guide: https://xdebug.org/docs/install#related_settings
# Configure xdebug.ini within a docker container
xdebug.mode=debug
xdebug.start_with_request=trigger
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
# Setup
# Verify the extension is setup and active
$ php -i | grep xdebug
<?php
# Verify the extension is setup and active from a webpage
phpinfo();
# Setup
<?php
# Verify the extension config and status
xdebug_info();
# Setup
# Setup
🔗 Documentation: https://xdebug.org/docs/all_settings#start_with_request
# Setup
# Add the environment variable in your shell to ALWAYS enable Xdebug
export XDEBUG_TRIGGER=1
# OR use on-demand activation by prefixing the environment variable before your command
XDEBUG_TRIGGER=1 wp my-command
# .. another example, to trigger within phpunit tests
XDEBUG_TRIGGER=1 phpunit
# Setup
<?php
function my_function() {
// ..
xdebug_break();
// ..
}
# Setup
🔗 Official guide: https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug
# Setup
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
}
]
}
# Setup
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/": "${workspaceRoot}"
},
"maxConnections": 1
}
]
}
# Setup
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/my-plugin": "${workspaceRoot}"
},
"maxConnections": 1
}
]
}
# Setup
# Setup
# Interactive debugging
Continue
Step over
Step into
Step out
Restart
Stop
# Interactive debugging
Lines where the editor will stop
# Interactive debugging
Editor panel
Breakpoints panel
Conditional breakpoints
(scope, global, and constants)
# Interactive debugging
Follow an expression value across steps
(variables, and expressions or statements)
# Interactive debugging
Sequence of function calls since the start
ie: Rewinding
# Interactive debugging
(click to dive into local state/variables THEN)
Execute any command within the current state!
ie God mode
# Interactive debugging
Alter execution flow using conditional breakpoints
ie God mode
# Interactive debugging
# Troubleshooting
<?php
// Add this to wp-config.php,
// or to any .php file that you can visit.
xdebug_info();
You can see xdebug settings and verify if all is as expected.
Also, Diagnostic log can offer insights on:
# Troubleshooting
- Try stopping on exceptions or errors if that's what you're getting as a result of the bug.
- If you see any specific strings where the error happens, try searching your codebase for that string, and put breakpoints around it to see if that's where the bug happens.
- Try adding a breakpoint as early as possible, and step through the code until you find where the bug happens. It might take time, but you'll get there eventually.
# Troubleshooting
- From one of the files in your workspace, try figuring out the remote path via something as dump as `die( __FILE__ );`, and adjust the `pathMapping` config accordingly.
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/test-block": "${workspaceFolder}"
}
}
]
}
# Troubleshooting
- Make sure you have the dependency files on your local machine, and add the mapping accordingly.
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/test-block": "${workspaceFolder}",
"/var/www/html/wp-includes": "/path/to/local/wordpress/wp-includes",
"/var/www/html/wp-admin": "/path/to/local/wordpress/wp-admin"
}
}
]
}
Remote debugging is the act of debugging a problem on a remote server.
# Remote debugging
Because sometimes you just can't replicate the bug on development environments, because of mismatched infrastructure setup, or simply because the data is different.
# Remote debugging
# Remote debugging
Browser
Server
Editor
Laptop
Server
Router
Private network
Internet
x.com
Public network
Debug session
Port forward
# Remote debugging
Laptop
Server
Router
Private network
Internet
x.com
Public network
Debug session
Port forward
2. Dynamic IP
1. Firewall
3. Travelling nomad! (Changing IPs)
Port Tunneling, eg: NRGOK, localtunnel
Port forwarding
xdebug.client_discovery_header
# Remote debugging
Laptop
Server
Router
Private network
Internet
x.com
Public network
Debug session
Port forward
2. Dynamic IP
1. Firewall
3. Travelling nomad! (Changing IPs)
# Remote debugging
Laptop
Server
Router
Private network
Internet
x.com
Public network
DBGP Proxy
# Remote debugging
Laptop
Server
Router
Private network
Internet
x.com
Public network
xdebug.cloud
# Remote debugging
Laptop
Server
Router
Private network
Internet
x.com
Public network
xdebug.cloud
# Remote debugging
# Profiling
Profiling is the systematic collection and analysis of runtime behavior metrics in your application, revealing where time is spent, memory is allocated, and functions are called, enabling data-driven optimisation decisions rather than gut feelings or assumptions about performance bottlenecks.
# Profiling
Profiling is like putting your code under a microscope that has multiple lenses - each lens showing you different aspects of how your code performs in real-world conditions. It's a systematic way to collect metrics about:
# Profiling
Local profilers
APM services
Xdebug
XHProf
SPX
....
NewRelic
DataDog
Tideways
....
# Profiling
Think of profiling like analyzing a busy restaurant kitchen. A profiler gives you statistical data about your code's performance, similar to knowing:
Tracing is like having security cameras in your kitchen that record every single movement. It captures the exact sequence of events, showing:
# Profiling
# Profiling
TRACE START [2024-01-01 12:00:00]
0.0000 > OrderProcessor->processOrder(123, array(2))
0.0001 > OrderProcessor->validateOrder(123, array(2))
0.0002 < OrderProcessor->validateOrder
0.0003 > OrderProcessor->calculateTotal(array(2))
0.0003 > array_column(array(2), 'price')
0.0004 < array_column = array(2)
0.0004 > array_sum(array(2))
0.0004 < array_sum = 30.0
0.0005 < OrderProcessor->calculateTotal = 30.0
0.0005 > OrderProcessor->saveOrder(123, array(2), 30.0)
0.0007 < OrderProcessor->saveOrder
0.0008 < OrderProcessor->processOrder = array(3)
TRACE END
# Profiling
# Profiling
# Profiling
# Profiling
Configure
Generate
Select Trace from xdebug ext.
View
Grab trace files
Visualise
xdebug.trace_format=3
xdebug.trace_output_name=trace.%u.%R
# Profiling
# Profiling
# Profiling
# Downlod plugins
wp plugin install --activate query-monitor
wp plugin install --activate https://github.com/humanmade/query-monitor-flamegraph/archive/refs/heads/master.zip
# Install the xhprof extension
sudo pecl install xhprof
sudo -E docker-php-ext-enable xhprof
sudo service apache2 reload
# Add xhprof sample enable after the first line (typically after <?php) in wp-config.php
grep -q "xhprof_sample_enable()" /var/www/html/wp-config.php || sed -i "1a ini_set( 'xhprof.sampling_interval', 1000 ); function_exists('xhprof_sample_enable') \&\& xhprof_sample_enable();" /var/www/html/wp-config.php
Caveat: Only shows main request, not API or AJAX calls.
# JS Debugging
Most browsers already have integrated dev tools into the browser to debug JavaScript code.
# JS Debugging
Bundler
1. Provide source maps
# JS Debugging
Editor
1. Create debug config
Browser
1. Start with debug flag
# For wp-scripts, one flag does the job:
npx wp-scripts start --webpack-devtool=eval-cheap-source-map
# OR
npm run start -- --webpack-devtool=eval-cheap-source-map
// webpack.config.js
{
// ...
devtool: "eval-cheap-source-map",
output: {
// ...
// Map to source with absolute file path not webpack:// protocol
devtoolModuleFilenameTemplate: 'file:///[absolute-resource-path]'
}
}
# JS Debugging
// launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"name": "Launch Chrome",
"request": "launch",
"url": "http://localhost:8888/wp-admin/",
}
]
}
# JS Debugging
// launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"name": "Launch Chrome",
"request": "launch",
"url": "http://localhost:8888/wp-admin/",
"pathMapping": {
"/wp-content/plugins/test-block": "${workspaceRoot}"
},
"sourceMapPathOverrides": {
"webpack:///./src/*": "${workspaceRoot}/*",
"webpack://test-block/*": "${workspaceRoot}/*",
"webpack:///*": "${workspaceRoot}/*",
"webpack:///./~/*": "${workspaceRoot}/node_modules/*",
"webpack:///node_modules/*": "${workspaceRoot}/node_modules/*"
}
}
]
}
# JS Debugging
// launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"name": "Attach to Chrome",
"request": "attach",
"port": 9222,
"pathMapping": {
"/wp-content/plugins/test-block": "${workspaceRoot}"
},
"sourceMapPathOverrides": {
"webpack:///./src/*": "${workspaceRoot}/*",
"webpack://test-block/*": "${workspaceRoot}/*",
"webpack:///*": "${workspaceRoot}/*",
"webpack:///./~/*": "${workspaceRoot}/node_modules/*",
"webpack:///node_modules/*": "${workspaceRoot}/node_modules/*"
}
}
]
}
# JS Debugging
"/path/to/Browser" --remote-debugging-port=9222 --user-data-dir=remote-debug-profile
For 'Attach' debug configuration, run the browser in debug mode:
# JS Debugging
linkedin: shady.sharaf
wp.org: shadyvb
github: shadyvb
Next up: