Debugging software is not exactly a fun job for developers. The
most widely used debugger for PHP still seems to be
a var_dump() statement,
possibly in conjunction with die() to
halt program execution at a certain point. While there is nothing
wrong using var_dump() statements
in itself, you still need to change the program code to debug a PHP
script. And worse, after you have finished debugging, you must
remove all var_dump() statements
again (well you should, at least). It may well be that a few days
later you'll find yourself adding the very
same var_dump() statements
to your code again because you need to go hunting another bug.
Of course, you could just comment out
the var_dump() statements,
but that looks really ugly in the code. Another option would be to
wrap the var_dump() in
conditional clauses, and only execute them when, say, a
constant DEBUG is
defined. This affects performance, because even if
the var_dump() statements
are not executed, the conditional clause must be executed. And
besides, it looks even uglier in the code.
As we have already learned in the second articles of this series,
having xdebug create a trace log might be a better option in this
case, because you do not have to change the program code. But a
trace log, even if only created for a part of the application,
provides us with a lot of information that may not be necessary for
the debugging process, so using a debugger is a much better
solution. A debugger allows you to pause program execution at any
time, inspect or modify the current variable values, and then
continue the program. By executing a program step by step, you can
closely watch the code doing its job, which hopefully helps you to
find out quickly where things go wrong.
Beyond var_dump,
debugging in PHP has been problematic for a long time, at least if
you were not willing to spend money on a commercial IDE that
supports debugging. With xdebug, open source debugging of PHP code
has - in theory - been possible for quite a while now. I say
theoretically because until recently no good and free debug client
for xdebug was available for both Windows and Unix.
This fall, the problem of having no release-quality cross-platform
xdebug client has been solved with the release of Eclipse PDT.
Eclipse PDT is a free IDE for PHP supporting xdebug out of the box.
So, without further ado, let us install Eclipse PDT to get started
with debugging.
Installing Eclipse PDT
Eclipse PDT (PDT is short for PHP Development Tools) is written in
Java, and thus works on most platforms where a Java Runtime
Environment is present. If you have no Java Runtime Environment
installed on your computer, you can download your copy
from
You can download a ready-to-go-package of Eclipse PDT
from http://www.eclipse.org/pdt.
You should choose the appropriate version for your platform, though
all packages are basically only compressed archives of the
necessary files to run eclipse. Still, the Windows version comes
with an .exe file
that starts Eclipse, which is way more user-friendly than calling
the Java classes directly.
As I write this article, the current Release Build version of
Eclipse PDT is R20070917. Choose the latest available version and
have some coffee ready, because the Eclipse PDT download is over
100 MB in size. But since it is a Java application, having a nice
cup of coffee while you wait for the download to complete should be
suitable. Once the download has completed, unpack the downloaded
archive and you are ready to start Eclipse PDT.
How debugging works
Before we get into the configuration of xdebug and Eclipse PDT, let
us have a look at how PHP debugging with xdebug actually works.
This will help you better understand the configuration described
below.
When debugging is enabled in php.ini,
xdebug controls the program execution in PHP, which basically means
that xdebug can pause and resume program execution at any time.
When program execution is paused, xdebug can retrieve information
about the current program state, like reading variable values. It
is even possible for xdebug to change the value of a variable, then
continue the script execution with a modified value.
The xdebug extension is a server, expecting client connections at a
certain configurable port. There are two protocols that can be used
to communicate between the xdebug client and the xdebug server, GDB
and DBGp. GDB is an older protocol, which has been superceded by
DBGp. By sending commands to the xdebug server, the xdebug client
acts as a sort of remote control for PHP, telling PHP to pause
execution, execute one step, or to continue the program execution.
The client is usually embedded into an editor or the IDE (in our
case, into Eclipse PDT), so you will not have to deal with the
debug protocol itself.
The PHP server with xdebug can run on a another system than the one
running the xdebug client. That is why xdebug is called a remote
debugger. For simplicity, we will set up the debugging server and
client on the same computer.
There are two different modes of starting a debug session with
xdebug. They are controlled by the php.ini setting xdebug.remote_mode.
The default setting isreq,
which makes xdebug always connect to the debug client when a script
is started. If you want xdebug to only connect to the debug client
on a breakpoint or an error in the script, you can
set xdebug.remote_mode to jit.
I would recommend keeping the default setting, which you can
achieve by putting noxdebug.remote_mode setting
into php.ini.
To actually start a debug session, you must pass a
parameter XDEBUG_SESSION_START to
the script by GET, POST, or cookie. The value of this parameter is
the debug session name, which should be unique at a given point in
time, so that xdebug can distinguish different debug sessions
running concurrently. To end a debug session, you need to
pass XDEBUG_SESSION_STOP to
the script.
Instead of manually dealing with the starting and stopping of debug
sessions, you can install a firefox
plugin that allows you to conveniently start
and stop a debug session with a mouse click.
Using Eclipse PDT, you will not even have to worry about the
browser plugin, as the IDE takes care of passing the appropriate
parameters to the browser. xdebug also requires setting of a IDE
key, which you also do not have to worry about, because Eclipse
sets it for you.
Configuring xdebug
Now let us configure xdebug debugging. Add the following settings
to php.ini:
xdebug.remote_enable=On
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_handler="dbgp"
Make sure you add these lines after
the zend_extension_ts line
that loads the xdebug extension. The first entry enables the
debugger. The second entry defines that the debug client runs
on localhost -
this could be any valid DNS name or IP address, if the client and
the server were not on the same computer.
The third setting defines the port the xdebug server expects the
client to listen on (which, strictly speaking, makes the client a
server, but let us not get confused about this). By default, the
port is 9000. This port is configured in Eclipse by default, and if
there is no compelling reason to do otherwise, you should keep the
default port. If you want to change the port, keep in mind that you
have to configure the same port number in Eclipse
and php.ini.
Also, make sure that no firewall gets into your way. When you start
Eclipse, you might see a warning that Java is trying to set up a
server, bind to a port, access the network, or perform some obscure
potentially dangerous action. Of course, it's not dangerous, it's
just the xdebug client trying to listen at port 9000. If you have
problems with debugging, check if there are any firewalls between
the debug server and the debug client that might block port
9000.
Last but not least, we have to tell xdebug which protocol the
client speaks. Eclipse PDT speaks DBGp, so you may not change this
setting.
Configuring Eclipse PDT
To configure Eclipse PDT, start Eclipse by double-clicking the
Eclipse executable. Create a new PHP project. Let us name the
project debug_test.
Now, create a file debug.php in
the project, add some code, then save the file.
Now let us configure Eclipse for debugging with xdebug. First of
all, we will configure Eclipse to launch projects in an external
browser instead of its internal browser. When an external browser
is configured, all debugging sessions will be launched in an
external browser as well. Using an external browser is not
absolutely necessary, but I prefer to work with Firefox instead of
Eclipse's internal browser. Choose Window from
the menu bar, then select Preferences (see
the following screenshot). Expand
the General subtree,
and click Web
Browser. Now, select the radio
button Use
external browser and
click Apply.
Eclipse PDT supports the Zend debugger and xdebug. By default, the
Zend debugger is activated. To change this setting to xdebug,
expand the PHP subtree
and the Debug subtree
of PHP.
Then, change PHP
debugger to Xdebug and
click Apply.
Now, choose Run from
the menu bar and click the entry Open
Debug Dialog. Then, double
click PHP
Web Page to create a new debug
configuration.
You will see a window with three
tabs, Server, Advanced,
and Common.
When not already selected, choose Xdebug as Server
Debugger. In the File
/ Project text field, you must enter the
path to the script you want to debug. This path must be relative to
your workspace. On my system, this is/debug_test/debug.php.
Click Browse and
select the file debug.php in
the debug_test directory.
Eclipse needs to know the URL matching the script filename and path
you just entered. This is required to highlight the currently
executed line in the source code.
The URL text
field shows the URL that is mapped to the filename. By default,
the URL text
field deactivated because the Auto
Generate checkbox is activated. If the
displayed URL does not match the URL you would type into your
browser to see the script you have specified
in File
/ Project, uncheck Auto
Generate and enter the correct URL in
the URL text
field. If thg script to debug requires any GET parameters, you can
append them to the URL given here.
Do not forget to click Apply to
save the changes. The following screenshot shows how the debug
configuration looks like on my system:
Change to the Advanced tab
and make sure that Open
in Browser and the radio
button Debug
All Pages both are checked. Now you can
close the configuration window and start a debugging session.
Debugging a PHP script
To start debugging a PHP script,
choose Run from
the menu bar and select Debug.
You can shortcut this by pressing the F11 key. Eclipse will ask you
wether you want to open the debug view. You should tick the
checkbox to remember this setting, otherwise you will be asked the
same question every time you start debugging.
The following screenshot shows Eclipse's debug view of
my debug.php script
(which contains some pointless code):
Eclipse has opened your system's default browser (or whatever
browser you have configured it to open). You will not see output in
the browser window yet, because Eclipse by default pauses script
execution on the first line of the script, as if a breakpoint were
set on this line. If you want to disable this behaviour, uncheck
the Break
at First Line checkbox in
the Breakpoint section
from the debug dialog configuration window.
As the screenshot shows, you can see the source code of the
debugged file, with the currently executed line marked with an
arroq to the left of the line number. In the above right area, you
can choose between different tabs.
The Variables tab
shows the current values of all variables in the current scope. The
superglobal variables are valid in every scope, so they are always
displayed. The Breakpoints tab
lets you view and edit all breakpoints in your script. Eclipse will
remember any breakpoints you have set on the code, even if you
close and restart Eclipse.
You can now continue program execution until the next breakpoint is
reached, execute just one step, or step into the next function, or
out of the next function scope by clicking the appropriate icons in
the Debug top
left area of the window. Stepping is useful when you have located
the problem area in your code and want to watch closely what is
happening. You will see the variable values change with each
step.
Changing Variables at Runtime
You can even change variable values during script runtime. While
this does not really fix a bug, it might be useful to provoke
certain errors without modifying the source code. To change a
variable, click the current value, modify it and
press Enter.
Breakpoints
A breakpoint pauses script execution and allows you to inspect
variable values, then continue the program. The program execution
is also paused if an exception occurs in your PHP code. To set a
breakpoint, right-click a line number in the source code, then
choose Toggle
Breakpoints from the context menu. You
can remove breakpoints in the same way, or remove them in
the Breakpoints tab
by right-clicking a breakpoint and
selecting Remove from
the context menu.
You can even add a condition to a breakpoint. Conditional
breakpoints will only pause the program execution when the given
condition is met. This is can be very useful when the same piece of
code is executed multiple times with different parametrization. To
add a condition to a breakpoint, right-click the breakpoint icon to
the left of the line number in the source code view.
Choose Breakpoint
Properties. You can remove conditions in the same way or
by right-clicking a breakpoint and
selecting Set
Condition from the context menu in
the Breakpoints tab.
Check Enable
Set Condition and enter a condition in
PHP code into the text field. In my debug.php,
the function test() is
called on line 11 and a breakpoint is set on this line. By adding
the condition $a
!= '' xdebug will only pause program
execution on this line when the local
variable $a is
non-empty at the time the breakpoint is reached.
To end a debugging session,
highlight Remote
Launch in the top left pane, then click
the Terminate icon
which is located between the Run and
the variousStep icons.
If you had Eclipse run the script in an external browser, you need
to close the browser window manually.
Conclusion
Remote debugging is a great interactive and non-intrusive way of
finding bugs in your PHP scripts. Instead of
putting var_dump() statements
into your code, or working your way through a long trace log
including parameter and return values, debugging gives you a
macrosopic view of critical areas in your code.