How to Use Xdebug for Advanced PHP Debugging

FavoriteLoadingAdd to favorites

You could just debug your PHP code using functions such as error_log, print, and var_dump, (and to be honest we’ve all done it, a lot!), but sometimes they just aren’t enough, and can actually slow you down while developing.

There must be a better way, surely?! Enter Xdebug, the rather awesome debugging and profiling tool for PHP.

In this post, I’ll take you through why Xdebug is amazing, getting it setup, how to use it, get the most out of it it, and some neat advanced uses all to make your life easier.

You can thank me later (in the comments) 🙂

How Xdebug Changed My Life

A few years ago I didn’t know debuggers existed, had never heard of Xdebug, and was quite happy using a function I’d cobbled together pinched from Stack Overflow in all my WordPress sites for debugging:

if ( ! function_exists( '_log' ) ) {
    function _log( $message ) {
        if ( WP_DEBUG === true ) {
            if ( is_array( $message ) || is_object( $message ) ) {
                error_log( print_r( $message, true ) );
            } else {
                error_log( $message );
            }
        }
    }
}

It was all I thought I needed until someone introduced me to Xdebug and my life changed. Excuse the hyperbole, but it happened!

When you are debugging using functions like error_log, you are only outputting the variables you define, which might not be what you need. For example, while troubleshooting some code, you add the function somewhere to debug a variable. You refresh your page and/or repeat the action so the debug line is executed, and then check your error log to look at the output. If this doesn’t give you any insight to the cause of the problem at hand, then you need to go back and add more debug lines to the code. Rinse and repeat.

Xdebug allows you to break during code execution and inspect all the variables in scope during a request. This means you have all you need to troubleshoot during only one iteration of this cycle. This can save a huge amount of time when tracking down issues, and helps make your development workflow more efficient.

Troubleshooting++ with Xdebug

Xdebug really shines when trying to troubleshoot a problem whose cause is completely unknown to you. If you know your function is broken, logging lines inside it is great and works well. But strange problem-causing behavior could be coming from anywhere in a project, like a plugin or WordPress core itself. How the hell do you track that down?

Xdebug’s breakpoints allow you to pause code at any point, which means the best thing to do is to break early and follow the code execution through with Xdebug (more on that later) until you spot something gone awry. To save time, you can progressively move breakpoints further along in the execution until you get closer to the potential issue, instead of breaking on code already analyzed as not the cause of the issue.

When you find the issue, you can actually change the values of variables on the fly after they have been assigned, so you can test potential fixes to the issue while debugging in the same request.

Debug Driven Development

Another great use of Xdebug is proactively during development itself, instead of reacting to issues with existing code. Think of this like Test Driven Development (TDD) but using the debugger first instead writing tests. I’m not even sure if Debug Driven Development (DDD) is a widely used term, but for me, I’ve used Xdebug to help me write new code in a couple of ways:

  1. Inspect existing arrays, objects, and class instances to find the data available to me in code, so I can use it in new code I write
  2. Immediately debug a newly-written piece of code to test it is working as expected

This isn’t something I do all the time, but Xdebug gives me this insight when I need it.

Installing Xdebug

Hopefully the benefits I’ve detailed have got you wanting to use Xdebug and you’re ready for some installation steps.

I’ve put together a list of the most common local environments with some handy links to getting Xdebug installed on them:

Do you work with a different local environment and need some guidance? Let us know in the comments.

PhpStorm Integration

News flash: I love PhpStorm! And guess what? PhpStorm has an awesome integration with Xdebug and is simple to set up. Other editors and Integrated Development Environments (IDEs) with Xdebug support are available.

Start Debugging

Once you’ve installed Xdebug and configured PhpStorm, you can start interactively debugging your code. This is done by setting breakpoints at certain lines of your code and telling PhpStorm to listen for incoming connections. When PHP executes a line that has a breakpoint on it, Xdebug will step in and pause execution allowing you to gain valuable insight to all that is happening during execution:

PhpStorm Xdebug debugging panel

The sidebar of the debug panel has various buttons for controlling the execution of the code. Here they are top down as they appear in the screenshot:

  • Resume Program – continue with the PHP execution
  • Pause Program – not available during debugging
  • Stop – halt the execution
  • View Breakpoints – bring up a window of all the breakpoints set in all files of the project
  • Mute Breakpoints – deactivate the breakpoints during execution (good for just finishing the request without breaking any further)
  • Restore Layout – resets the default view of the Debug panel
  • Settings – tweak the debugger display
  • Pin Tab – always show the Debug panel
  • Close – close the panel and choose to disconnect the debugger from the connection or terminate it completely
  • Help – links to JetBrain’s online help docs for the Debug panel

The top bar of the panel controls how the debugger traverses the code so you can inspect different parts of the codebase:

  • Show Execution Point – jumps back to where the program is broken
  • Step Over – execute and move to the next line of the file
  • Step Into – if the next line has one or more functions, move the debugger into those to step through
  • Force Step Into – step into a function that is marked as skipped
  • Step Out – move the debugger out of the current function back to the function that called it
  • Run to Cursor – execute all the way to the line the cursor is on
  • Evaluate Expression – execute PHP while the debugger is running (think of this like Chrome’s JS console)
  • Show Values Addresses – displays the memory address of objects
  • Hide Empty Superglobals Variables – removes some noise from the variables list
  • Add Method to Skip List – mark method to be skipped next time

Breakpoints are added by clicking in the left-hand gutter of the code, along the line you want at which you want to break. PhpStorm also allows you to set conditional breakpoints, where you add PHP logic to control when a breakpoint actually fires:

PhpStorm add conditional breakpoint

When troubleshooting, it is often helpful to inspect and watch the value of a variable all the way through the execution of a request to see when it changes. PhpStorm allows you to add variables to a list that it watches and displays in a separate ‘Watches’ panel, away from all the noise of the main ‘Variables’ panel. You can watch a variable by either right-clicking the variable in the file during debugging and selecting ‘Add to Watches’ or doing the same from the variable in the ‘Variables’ panel:

PhpStorm add variable to watch list

Stack Trace

Enabling Xdebug gives you, by default, an extended stack trace for any errors, notices or warnings that are written to the PHP log:

[26-Jul-2017 16:06:21 UTC] PHP Notice:  Trying to get property of non-object in /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/functions.php on line 302
[26-Jul-2017 16:06:21 UTC] PHP Stack trace:
[26-Jul-2017 16:06:21 UTC] PHP   1. {main}() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/index.php:0
[26-Jul-2017 16:06:21 UTC] PHP   2. require() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/index.php:3
[26-Jul-2017 16:06:21 UTC] PHP   3. require_once() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-blog-header.php:19
[26-Jul-2017 16:06:21 UTC] PHP   4. include() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/template-loader.php:74
[26-Jul-2017 16:06:21 UTC] PHP   5. get_header($name = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/404.php:2
[26-Jul-2017 16:06:21 UTC] PHP   6. locate_template($template_names = *uninitialized*, $load = *uninitialized*, $require_once = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/general-template.php:45
[26-Jul-2017 16:06:21 UTC] PHP   7. load_template($_template_file = *uninitialized*, $require_once = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/template.php:647
[26-Jul-2017 16:06:21 UTC] PHP   8. require_once() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/template.php:688
[26-Jul-2017 16:06:21 UTC] PHP   9. do_action($tag = *uninitialized*, $arg = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/header.php:27
[26-Jul-2017 16:06:21 UTC] PHP  10. WP_Hook->do_action($args = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/plugin.php:453
[26-Jul-2017 16:06:21 UTC] PHP  11. WP_Hook->apply_filters($value = *uninitialized*, $args = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/class-wp-hook.php:323
[26-Jul-2017 16:06:21 UTC] PHP  12. dbi_theme_body(*uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/wp/wp-includes/class-wp-hook.php:298
[26-Jul-2017 16:06:21 UTC] PHP  13. dbi_theme_render_part($part = *uninitialized*, $args = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/functions.php:137
[26-Jul-2017 16:06:21 UTC] PHP  14. include() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/functions.php:11
[26-Jul-2017 16:06:21 UTC] PHP  15. dbi_theme_is_products_page() /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/parts/nav/nav.php:15
[26-Jul-2017 16:06:21 UTC] PHP  16. dbi_theme_is_product_page($product = *uninitialized*) /Applications/MAMP/htdocs/deliciousbrains.com/public_html/content/themes/deliciousbrains/functions.php:315

The extended stack trace is helpful on its own, but, coupled with PhpStorm, you get a dynamic view of the trace when debugging. This dynamic view gives you an interactive history of what code has been executed up to the breakpoint or current point of the execution:

PhpStorm Xdebug dynamic stack trace

Because I rely on wp-content/debug.log or the PHP error_log to alert me to issues, but I use PhpStorm to see the stack trace, I end up disabling the extended (and very noisy) stack trace in the log by putting this in my wp-config.php file:

if ( function_exists( 'xdebug_disable' ) ) {
    xdebug_disable();
}

Advanced Use

Mastered the basics? Ready for more? Here are some advanced ways you can use Xdebug to improve your development workflows.

Profiling

When you really need to investigate performance issues with your code or website, one of the best tools we’ve found is Blackfire, which we’ve written about before. But Xdebug also profiles for you and PhpStorm can interpret the results, which is great as it means you never have to leave PhpStorm! 😂

To enable the profiler, simply edit your php.ini file to add or uncomment these lines in the Xdebug section:

xdebug.profiler_enable=1
xdebug.profiler_output_dir="/Applications/MAMP/tmp"

Then Xdebug will create a profile log file for each execution of your code. Remember to disable the profiler when you’re done so you don’t fill your hard drive with log files! Alternatively set the output directory to the /tmp directory for your OS.

These logs can then be analyzed in PhpStorm by navigating to Tools > Analyze Xdebug Profiler Snapshot and selecting the log file. The visualization isn’t as in-depth as Blackfire or using something like KCachegrind but it is still is a great way to analyze bottlenecks in your code:

Analyzing Xdebug profile log in PhpStorm

Remote Debugging via SSH

You can troubleshoot bugs only if you can recreate them on your development environment. Of course when it comes to running a website, we recommend having your development environment as close to production as possible, and you debug on a near-as-possible copy of the production database, but sometimes bugs and oddities will only happen on production. No one wants to start messing around on a live site, editing files to add logging lines. Don’t worry PhpStorm and Xdebug have you covered!

You can install Xdebug on a remote server and debug the code execution locally using Xdebug and PhpStorm. This feature is a lifesaver and suprisingly simple to set up. Just make sure to turn off Xdebug when you are finished, so your site’s performance isn’t impacted by Xdebug unnecessarily.

Conclusion

I hope this has been a good introduction to how powerful and valuable using a debugger like Xdebug is for your development workflow. For me, it is a huge time saver and I couldn’t imagine developing without it in my toolbox.

Do you use Xdebug or another debugger? Have I missed any awesome features or do you have any tips? Let me know in the comments below.

The post How to Use Xdebug for Advanced PHP Debugging appeared first on Delicious Brains.

Click to visit original source at DeliciousBrains.



Categories: Wordpress

Tags: , , , , , , ,

Subscribe

Subscribe to this Journal

Subscribe to our Saturday morning digest of each week's new content. ITS FREE!

Email address