Debugging PHP Web Sites with Zend Studio/MacPorts/Mac OS X

For much of my day I am trudging through PHP trying to trace the path of some errant bit of code. Thankfully I’m running my development off my local machine so it makes things a little easier. I’m using Zend Studio as my primary IDE and have installed the latest versions of PHP and such using MacPorts (which I highly recommend) so the entire system (DB & all) can work comfortably sitting on my lap while I sit on the couch and watch the latest episode of Big Bang Theory (also highly recommended).

I was however, still falling back to the hacky debugging method of die() and echo to figure out what was going on in my PHP scripts. Crude I know but admit it, we’ve all done it. After working on a recent Android project and being spoiled by the breakpoint debugging I decided it was about time to get my debugging environment set up properly for PHP–and it was quite easy!

Installing Zend Debugger

First, I downloaded the Zend Debugger binaries from the Zend site and put them along side my Zend Studio install:

/Applications/Zend/ZendDebugger-5.2.26-darwin9.5-x86_64/...

Next, I created a zend.ini in my PHP install. I’m using MacPorts so my php.ini was located at /opt/local/etc/php5/php.ini but I opted to use an additional ini file (that was automagically loaded) at /opt/local/var/db/php5/zend.ini instead:

sh-3.2# php -i
phpinfo()
PHP Version => 5.3.1
System => Darwin Jeffrey-Sambellss-MacBook-Pro.local 10.3.0 
    Darwin Kernel Version 10.3.0: Fri Feb 26 11:58:09 PST 2010;
    root:xnu-1504.3.12~1/RELEASE_I386 i386
Build Date => Feb  4 2010 00:05:00
Configuration File (php.ini) Path => /opt/local/etc/php5
Loaded Configuration File => /opt/local/etc/php5/php.ini
Scan this dir for additional .ini files => /opt/local/var/db/php5
Additional .ini files parsed => /opt/local/var/db/php5/iconv.ini,
/opt/local/var/db/php5/mbstring.ini,
/opt/local/var/db/php5/postgresql.ini,
/opt/local/var/db/php5/zend.ini

This zend.ini simply enabled the Zend Debugger and set some basic permissions:

sh-3.2# cat /opt/local/var/db/php5/zend.ini
zend_extension=/Applications/Zend/ZendDebugger-5.2.26-darwin9.5-x86_64/5_3_x_comp/ZendDebugger.so
zend_debugger.allow_hosts=127.0.0.1
zend_debugger.expose_remotely=always

so now I had the debugger installed:

sh-3.2# php -v
PHP 5.3.1 (cli) (built: Feb  4 2010 00:05:45) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2009 Zend Technologies
    with Zend Debugger v5.2, Copyright (c) 1999-2009, by Zend Technologies

The Debug Profile

The easiest way to continually debug a site in Zend Studio is to set up a profile for the url you’ll be debugging. To do so, I selected Run > Debug Configurations... and then double clicked PHP Web Page. I needed to do a little bit of setup here to create the correct profile.

Server Tab Settings

First, I set the Server Debugger to Zend Debugger then selected New next to the PHP Server option since I’m using my own PHP and Apache install from MacPorts.

In the new server dialog, I entered a name for the server configuration and the url that points to the document root. In my dev environment I simply use localhost so I entered http://localhost (you may need to enter something else depending on how you set up apache).

Next in the new server dialog, I set a path mapping for the root of the url to the actual document root in the project. I’m using a Zend Framework project that is configured to use the /public folder from the project as the document root so I added a mapping for / to /MyProjectName/public

The rest of the settings in the new server dialog were unimportant since I’m developing locally on my own machine.

Back in the Server tab of the debug profile, I set the File to the primary index file (again, mine was /MyProjectName/public/index.php) and I opted to automatically pause at the beginning of each debug session by selecting Break at First Line.

I was also sure to deselect the autogenerate option for the url and simple set the editable portion to /. If not, I ended up with debug urls like http://localhost/MyProjectName/public/index.html instead of just http://localhost.

Advanced Tab Settings

I just left Open in Browser checked and Debug All Pages. This allows me to select this profile for any debugging since everything runs through the index.php bootstrap file.

Common Tab Settings

Under common I opted to display this new profile in the Debug menu for easy access but other than I was done.

Actually Debugging

With everything now set, I just select my new debug profile from the debug menu and voila! The browser opens and the script halts at whatever breakpoints I’ve specified. I can then choose to advance step by step or browser through the local variable scope. So much nicer and faster than die() or echo.