XDebug is one of the essential PHP extensions for PHP developers. The name is a bit misleading, as it implies that it is just a debugging tool. This can put people off, since getting the debugger to work with your personal editor requires an understanding of networking, and can often be confusing. Even if you can't immediately get XDebug to work as a debugger, it is still valuable as a stack trace tool, or as a color coded replacement for PHP's var_dump, or as a code coverage analysis tool, and most importantly as a profiler. In this tutorial I'll attempt to cover installation, and most of XDebug's standard features.
Install XDebug
Anyone who spends any time doing PHP development soon finds that PHP is not a one size fits all world. Thanks to its efforts to be a portable and extensible platform, PHP offers developers a wide array of platforms, installation methods, and configurations. Since XDebug needs to play within the ecosystem of PHP, there are a variety of different ways you can install it including compiling it from source.
The important thing to keep in mind is that XDebug is something you want installed on your development server, not on your production server! For that reason, I'm not going to cover compiling from source. All the installation options are covered in the XDebug manual.
For most people, the easiest way to install XDebug is to use PEAR/PECL. On a unix system that involves running pecl install.
# pecl install xdebug
Upon completion, you can check that everything has installed correctly.
debian:~# pecl list
Installed packages, channel pecl.php.net:
=========================================
Package Version State
xdebug 2.0.5 stable
On a Debian system, the build process included adding an ini file in an include directory that php utilizes to configure its modules, and I did not need to make further adjustments -- just restarted apache. On a 64bit Centos 5.5 install, the php.ini needed to be manually updated. In order to find the location of the xdebug.so, you can run pecl list-files.
[root@localhost ~]# pecl list-files xdebug
Installed Files For xdebug
==========================
Type Install Path
doc /usr/share/pear/doc/xdebug/contrib/tracefile-analyser.php
doc /usr/share/pear/doc/xdebug/contrib/xt.vim
doc /usr/share/pear/doc/xdebug/Changelog
doc /usr/share/pear/doc/xdebug/CREDITS
doc /usr/share/pear/doc/xdebug/LICENSE
doc /usr/share/pear/doc/xdebug/NEWS
doc /usr/share/pear/doc/xdebug/README
src /usr/lib64/php/modules/xdebug.so
When you run the pecl install you'll see an erroneous message indicating that you should add an extension=xdebug.so to your php.ini. IGNORE THIS!!!
You actually need to load XDebug using either:
; Enable xdebug
zend_extension="/usr/lib64/php/modules/xdebug.so"
--or if you're setup with the threaded environment that has enabled "thread safety" then:
; Enable xdebug
zend_extension_ts="/usr/lib64/php/modules/xdebug.so"
The cleanest way to set this up under Centos is to create a file in the /etc/php.d directory named xdebug.ini. You can also just manually add the lines above to your php.ini file. The comment "; Enable xdebug" isn't necesssary but it's helpful for documentation purposes to have it, so why not?
If you've followed these instructions and you still don't see xdebug in your phpinfo() page, make sure you have permanently disabled selinux, as it can interfere with the ability for php to load the XDebug module.
Once you've installed XDebug, an XDebug section will be visible in the phpinfo() page, along with a list of default settings.
var_dump()
One of the first things that XDebug will do by default is replace php's var_dump() with a nicer version that is also configurable in a variety of ways.
In this example, I've inserted:
var_dump($mainframe); die();
--into the index.php file for the CMS joomla. The $mainframe object is the main application/controller object for Joomla, so inspecting it might be useful for understanding more about how Joomla works. Without XDebug, this is what the output looks like:
object(JSite)#2 (7) { ["_clientId"]=> int(0) ["_messageQueue"]=> array(0) { } ["_name"]=> string(4) "site" ["scope"]=> NULL ["_errors"]=> array(0) { } ["requestTime"]=> string(16) "2010-10-09 23:56" ["setTemplate"]=> string(13) "rhuk_milkyway" }
With it turned on we get this:
XDebug adds nesting, color coding and scope identification to the output.
Consider a more complicated object:
Trying to make sense out of all this jumbled output isn't easy. With XDebug you can see the forest through the trees.
Stack Trace dump
A stack dump is what PHP spits out when you have a runtime error in your script. During development you want to have display_errors turned on, so you can easily see these when they occur. Vanilla PHP might show you something like:
Fatal error: Uncaught exception 'Zend_Controller_Dispatcher_Exception' with message 'Invalid controller specified (tutorials)' in /var/sites/flingbits.com/library/Zend/Controller/Dispatcher/Standard.php:248 Stack trace: #0 /var/sites/flingbits.com/library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http)) #1 /var/sites/flingbits.com/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch() #2 /var/sites/flingbits.com/library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run() #3 /var/sites/flingbits.com/public/index.php(10): Zend_Application->run() #4 {main} thrown in /var/sites/flingbits.com/library/Zend/Controller/Dispatcher/Standard.php on line 248
With XDebug, your Stack dump looks like this:
The XDebug version is not only a lot easier to read, but it also adds profiling and memory usage information to the trace. However, there are a number of additional options you can turn on to make this even more useful.
xdebug.collect_params
This setting will provide you a variable level of information about parameters being passed. Setting this to "4" gives you the maximum amount of parameter information available.
xdebug.collect_params=4
xdebug.show_local_vars=1
This is a kitchen sink setting that will dump out every variable in the local scope. In a smaller application or when confronted with a particularly confusing problem, this might be useful, but in most cases where you have a script of any sophistication, it simply produces too much output.
Dumping superglobals
You can add some or all of the various superglobals to your stack trace, by setting the xdebug.dump.SUPERGLOBALNAME=*.
For example:
xdebug.dump.SESSION=*
xdebug.dump.COOKIE=*
xdebug.dump.GET=*
xdebug.dump.POST=*
xdebug.dump.FILES=*
xdebug.dump.REQUEST=*
xdebug.dump.ENV=*
xdebug.dump.SERVER=*
Most of the time, you will probably want to limit the output to a handful of commonly useful variables, so instead of setting the variable to the wildcard '*', you can instead pass a list of the specific variables you are interested in.
For example:
xdebug.dump.SERVER=SCRIPT_FILENAME,REQUEST_METHOD,QUERY_STRING,HTTP_COOKIE,REMOTE_ADDR
Profiling
The XDebug profiler outputs "cachegrind compatible files" that can be analyzed with a variety of tools, depending on your platform. If you're developing on a linux workstation use kcachegrind, or on windows wincachegrind.
The best way to enable profiling is to set XDebug so that you can pass a parameter to the script via a GET, POST or COOKIE that will enable it. There's also a setting that defines the name of the cachegrind file(s) generated. I recommend these settings, and by default your files will be deposited in the /tmp directory of the server.
;profiling
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_name=cachegrind.out.%s.%t
Now you can selectively trigger profiling by passing a GET param in the URL:
http://www.gizlocal.com/?XDEBUG_PROFILE
Once the script has run, you should find the profile output file in your temp directory. The file will be namedcachegrind.out.{path_and_filename}.{timestamp}
Using these settings will allow you to generate multiple profilings for the same script, as well as allowing you to easily identify the script that actually generated the profiling data.
debian:/tmp# ls -lath | grep cachegrind*
... 4.5M 2010-11-16 13:04 cachegrind.out._var_sites_flingbits.com_public_index_php.1289941492
Once you have a profiling data file, you will need to load it into an analysis tool. There are analysis tools available for most common operating systems, although the features of the various tools differs. For an Xwindows Linux workstation, KCachegrind provides the timing and call data as well as graphical visualizations like the "Call Graph" screen. WinCacheGrind is a native windows application which doesn't provide graphs, but does show the calls and timings, and allows you to sort the profile data in a variety of ways. Here's a screenshot showing the functions which take the most time.
Regardless of the tool, your primary goal is to determine which blocks of code are taking the most time. The analysis tool will show you how many times each function was called, along with aggregate and average execution times. Often you will have functions or methods that call other functions. The local time is totalled seperately from the cumulative time so you can determine where the majority of the time is being spent.
Debugging
Getting the XDebug remote debugger to work with your favorite IDE will probably require looking up configuration instructions for your IDE. These settings are typical, and reflect the process of setting things up to work with Eclipse PDT.
Remember that whenever you make changes to any of these serverside settings, in the php.ini or an included .ini, you must restart Apache!
The first thing you need to do is configure XDebug on your server to turn on remote debugging support. While a number of these settings are also the default it doesn't hurt to include them, in case you need to make tweaks.
;Debugger
xdebug.remote_enable=1
xdebug.remote_mode=req
xdebug.remote_port=9000
xdebug.idekey=ECLIPSE_DBGP
xdebug.remote_handler=dbgp
xdebug.remote_host=10.1.0.2
Reviewing these settings:
-- you need to enable the debugger using xdebug.remote_enable=1.
-- The xdebug.remote_port is the port the debugger will use to connect back to your IDE once the debugging session is started. It defaults to port 9000.
-- xdebug.idekey needs to be set to whatever your IDE will use to instantiate the session. This gets passed as a url parameter by the eclipse debugger as ?XDEBUG_SESSION_START=. For Eclipse with PDT, the session id will be ECLIPSE_DBGP. For other IDE's or editors that support XDebug this could very well be something different. Ultimately it is an identification mechanism, which simply has to be agreed upon for the editor to connect to XDebug. When everything is setup correctly, you can expect to see something like this in the browser URL when your eclipse debug sessions starts.
http://www.gizlocal.com/?XDEBUG_SESSION_START=ECLIPSE_DBGP&KEY=12900687508406
-- xdebug.remote_handler specifies the debug protocol, which in this case should be dbgp.
-- Last but not least, the xdebug.remote_host needs to be an IP address for your workstation that can be reached by the server. If for example, your workstation is behind a NAT firewall, you'd have to setup a port forward rule for your workstation that forwards port 9000 traffic back to your workstation. If you're using a WAMP or virtual server environment using VMware or Sun Virtualbox, then chances are this is going to be an internal IP address like the one I included in my example. I highly recommend using a virtual server for your development environment.
If you're not sure how to do this, I have a detailed 2 part article on setting up your own virtual Centos Lamp server running inside Sun Virtualbox on a PC running Windows here.
Configuring Eclipse PDT for XDebug
There are many things that can go wrong with the debugging configuration. Keep in mind that Eclipse PDT's debugger is generic and setup to support different debuggers. This section is not meant to be exhaustive, but should give you an idea of how to get started.
When the debug session starts and your workstation browser is opened, you should see a valid URL (see above) and the page should be blank. If the full page is displayed this is a good indication that you need to check your settings, and that Eclipse didn't connect to XDebug!
When configuration is complete you will open the PHP Debug perspective, and choose a debug configuration. For any specific script you want to debug, you'll need to create a Debug configuration for it. In other words, if you reach a script via a particular URL, you'll need a debug configuration unless it can be reached via another script that you have already setup. For a framework style application, you can set skip to the points you're interested in via breakpoints, but you'll need to have the files you want to set breakpoints in, open in the IDE, and then once you start the debugger, you switch to the file you want to set the breakpoint in, and choose "Run to line". It's not pretty but it works.
From the Menu choose the Run | Debug Configurations panel.
-- When you get into this panel, give the Debug configuration a name representing the script. This will make it easy for you to choose the right config to debug. In this example, I called it "Index" because I'm debugging the index.php of this framework application.
-- Set the server debugger to XDebug.
-- Browse your project and find the script you want to debug. The script has to actually be executable.
-- Uncheck URL - Auto Generate. This is bugged in my version of Eclipse PDT, and it also seems to add slashes in the neighboring path box that you want to clear out whenever you see them.
-- Save
-- Reopen your freshly created debug configuration, and now "Add" a new PHP Server.
-- Give this a name representing your development server that is running XDebug.
-- Enter the domain name, and provide a path if you've got an application running in a subdirectory off the site root. Leave off the closing '/'!
-- The configuration wizard will take you to the next step, which is adding at least one "Path Mapping".
-- This maps the base location for your workspace files to the path on the server.
Ready to debug?
If everything has gone as planned you should now have a working configuration. Change to the "PHP Debug" perspective. Click on the Debug button, and choose your Debug configuration based on the name you gave it when you set the configuration up in eclipse. You can switch to the browser and should see it loaded with the proper url and the added XDebug parameters discussed previously. The screen should be blank and Eclipse should load up the debugged file into the editor, fill the variable window and set things so that you can step through the code using the "step into", "step over", and "step and return" buttons on the debug button bar.
Summary
XDebug is more than a debugger, even though for PHP it can be used as one. It's an invaluable development tool that will help you during the development process. Hopefully you learned more about how to set it up and start to make use of it. If you have questions or comments, reply here or make a thread in the forum.
Original Article Source: http://www.flingbits.com/tutorial/view/xdebug-for-developing-debugging-and-profiling-php