沧海九粟 / 性能测试 / Introducing xdebug

0 0

   

Introducing xdebug

2008-03-21  沧海九粟

Other Articles in the Series

Part One: Introducing xdebug
Part Two: Tracing PHP Applications with xdebug
Part Three: Profiling PHP Applications With xdebug
Part Four: Debugging PHP applications with xdebug
Part Five: Creating Code Coverage Statistics with xdebug


This article is the first installment of a five-part series of articles covering xdebug, a free and open source swiss army knife tool for PHP developers. xdebug is a PHP extension created by Derick Rethans, one of the PHP core developers. This week, we will show you how to install xdebug and introduce you to some of the basic features. In the subsequent parts of this article series, we will have a closer look at one of xdebug‘s main features, namely tracing, profiling, debugging, and code coverage.

Installing the xdebug extension

First of all, we need to install xdebug. As I write this article, the current version is 2.0.1. Since the internal PHP APIs may change between different PHP releases, you must make sure that the version of xdebug you are installing matches the PHP version you are using.

xdebug does not work with any PHP versions before 4.3, and will probably not yet work with PHP 6. This is not a real problem, however, since PHP 4 will reach its end of life in 2008, and PHP 6 will probably not be available before the end of 2008. This gives you enough time to get used to xdebug so you can use it as a helpful tool when it comes to migrating your PHP code to work with the next major or minor PHP release.

Installing on Unix

Before we dig into xdebug‘s features, let us get the installation done. On Unix, you can try installing xdebug through PECL, the PHP extension community library. The PECL installation does not work on all systems, though. If the PECL installation does not work out for you, you must compile xdebug from source. But first, try the PECL installation:

pecl install xdebug

If the PECL installation does not work for you, you need to compile xdebug from source. In addition to a C compiler, you will need appropriate versions of the usual build tools (Autoconf, Automake and Libtool). If they are not already installed on your system, you can usually install them by running apt-get install build-essential on Ubuntu or Debian. When configuring xdebug, you will get an error when any required tool is missing. In this case, just install the missing tool, then configure xdebug again.

Furthermore, two helper programs, phpize and php-config that are a part of PHP, are required. If you have not compiled PHP from source, you will probably have to install the developer packages using your distribution‘s package manager. On Ubuntu or Debian, you can install the PHP development tools using a command like apt-get install php5-dev.

Please note that phpize and php-config must match the PHP version you are using, so do not just copy them to your system from some other PHP installation. When your development tools are in place, you can download and compile xdebug:

wget http://xdebug.org/link.php?url=xdebug201
tar -xzf xdebug-2.0.1.tgz
cd xdebug-2.0.1
phpize
./configure --enable-xdebug --with-php-config=/usr/bin/php-config
make
cp modules/xdebug.so /usr/lib/apache2/modules/xdebug.so


The php-config path may be different on your system, and depending on the your Apache installation directory, you may need to copy xdebug.so to another directory. Instead of copying the file, you can of course create a link as well.

Installing on Windows

If you are a Windows user, you can download a compiled DLL from xdebug.org. Select the PHP version you are using and click the appropriate link in the Windows modules section in the right column of the page.

You must use the non-debug version of PHP with xdebug. If you have downloaded PHP from php.net, debugging should not be enabled. When in doubt, check the Debug Build entry in the phpinfo() output.

I would recommend putting the downloaded DLL into PHP‘s extension directory ext, which should be a subdirectory of your PHP directory. You can put the DLL to any directory, provided that you state the full path to the DLL in php.ini.

Activating the xdebug extension

Now you have the xdebug extension ready, either as a shared object on Unix or a DLL on Windows. To activate xdebug, you must add an entry to php.ini. On Windows, use:

zend_extension_ts="c:\php\ext\php_xdebug-2.0.1-5.2.1.dll"

On Unix, use:

zend_extension="/usr/lib/apache2/modules/xdebug.so"

instead. The path to PHP‘s extension directory or Apache‘s module directory may differ on your system. Make sure you specify the full absolute path, not a relative path.

Please note that on Windows, we use zend_extension_ts, which means that a thread-safe extension is loaded, whereas on Unix, we a non-threadsafe extension is loaded. Depending on your system setup, you must decide for yourself wether you need a thread safe or non-thread-safe extension. If you are not sure wether your PHP installation is thread-safe, check the Thread Safety entry in the phpinfo() output.

You should not load any other Zend extensions while working with xdebug, because they would probably use the same internal mechanisms in the Zend engine, which usually calls for trouble. Not all Zend extensions work together with xdebug. Since you will probably use xdebug on a development system rather than a live system, this is no serious limitation. The most important rule is to not mix xdebug with other PHP debugger extensions.

Having restarted your web server because we changed php.ini, you can check the output of phpinfo() or run php -m at the command line. In each case, xdebug must be listed twice, once as a PHP extension, and as a Zend extension as well.

Take care when you are updating PHP with xdebug installed. If the internal APIs change between the PHP versions (which does not happen on every new version, but will certainly happen when you are close to a project deadline), the new version of PHP will probably not start or at least give you funny errors. If need be, you can always get away with disabling xdebug, at least temporarily, to get an updated PHP version to work and re-enable xdebug as soon as a new version is released that works with the newer API version.

There are quite some php.ini switches to configure xdebug, but most of them have sensible deafult values, so we can start using xdebug without worrying about configuration settings right now. We will take a look at the most important configuration settings as we need to.

Improved var_dump() output

Let‘s face it: the most widely used PHP debugger is var_dump(). Given the dynamic nature of PHP, and the fact that PHP is a scripting language, there is nothing wrong in using var_dump() - I do it all the time. The drawback is that you have to modify your program to debug it. The more var_dump() statements you put into your code, the more likely it is that you‘ll forget to remove them all once you have found and fixed your bug.

xdebug offers interesting alternatives to the extensive use of var_dump() statements for debugging your code, which we will get to know in the next and last article of this series. But for now, you‘ll be glad to hear that xdebug even improves our beloved var_dump() debugger.

When the xdebug extension is loaded, the output of PHP‘s var_dump() function is automatically beautified for better readability, as the following screenshot shows:

You can configure the way xdebug formats the var_dump() output by various php.ini settings. First of all, you can change the length of strings that xdebug displays. The default value is 512; longer strings are automatcally truncated.

Wether you want xdebug to display the full string depends on the situation, and the size of data you work with. If you work with big strings, the var_dump() output can get long and hard to read, thus is is a good idea truncate strings for better overview. On the contrary, if you are looking for a specific value in the output, you will probably want the strings to be displayed in full length.

To change the string length xdebug displays, add

xdebug.var_display_max_data=<your preferred value>

to php.ini and restart your web server so that this setting takes effect. Alternatively, just like you can change various php.ini settings of the PHP core at script runtime by ini_set, you can add

ini_set(‘xdebug.var_display_max_data‘, <your preferred value>);

on top of your script to make sure the ini_set-command is executed before your first var_dump() is encountered, otherwise your runtime setting will not take effect. Configuring xdebug at runtime with ini_set saves you from restarting your web server every time you want to modify the xdebug configuration and makes you much more flexible.

You can also control the number of array elements or object properties that xdebug displays. This is done by modifying the xdebug.var_display_max_children setting, which defaults to 128. This value should be sufficient to display all properties of your objects, but if you work with large arrays, you might still need to increase this value.

If you work with nested objects and arrays, you may want to modify the xdebug.var_display_max_depth setting. This setting has a default value of 3, which means that three nested levels of array elements and object relations are displayed.

You can also dump the values of the superglobal variables using the xdebug function xdebug_dump_superglobals(). As the superglobals, especially $_SERVER, are arrays that contain many values, you must explicitly tell xdebug which array keys you would like to see. To do this, set xdebug.dump.<superglobal name> where <superglobal name> is one of GET, POST, SERVER, COOKIE, FILES, REQUEST, or SESSION. Use the array key(s) that you want xdebug to display as argument, using a comma-separated list if you want to display more than one key per superglobal variable. You can use * as a wildcard to display all keys, which can be useful for $_GET and $_POST.

Using

ini_set(‘xdebug.dump.SERVER‘, ‘HTTP_HOST, SERVER_NAME‘);

in your PHP script or setting

xdebug.dump.SERVER=HTTP_HOST, SERVER_NAME

in php.ini will display the value of $_SERVER[‘HTTP_HOST‘] and $_SERVER[‘SERVER_NAME‘]. To display all GET parameters that were passed to the script, use

xdebug.dump.GET=*

By default, xdebug does not dump undefined values, but just skips the respective array keys. To force display of undefined values, set xdebug.dump_undefined to On. I would recomment turning xdebug.dump_undefined on, because it can be quite confusing if you.

You may wonder why xdebug supports configuring displaying select items of superglobal variables, when the same effect could be achieved with a number of var_dump() statements. First of all, you can have values of different superglobals displayed in one spot in a very readable way. Second, and more imporant, xdebug does not only show these superglobals when you call xdebug_dump_superglobals(), but also when any error occurs in your script, as we will see in the next section.

Better error messages

xdebug also improves the way PHP displays error messages by automatically displaying a stack trace along with every PHP error message, warning and notice. This stack trace lists the history of function calls that lead to an error. As PHP programs become more and more object-oriented, sometimes errors tend to show up deep inside libraries or helper objects. The stack trace allows you to quickly find out where the code piece that caused an error was originally called from.

Since version 5.0, PHP also has a native function debug_print_backtrace() that displays the stack trace, but you‘d have to call this function explicitly each time an error occurs, which means that you would have to create a custom error handler just to display stack traces along with error messages. Also, the stack trace created by xdebug is easier to read than the output of the native PHP function.

Like PHP itself, xdebug only displays error messages when display_erorrs is set to On in php.ini. On a development system, this should be the case. If not, add

ini_set(‘display_errors‘, ‘Off‘);

to your script to change the setting at runtime.

Looking at this stack trace, you can see that the function foo() was called, which called bar(), which in turn called baz(). In addition to the name of the calling functions and where they are located in the source code, xdebug displays a timestamp and the amount of memory used by the script when the function was called.

In the previous section, we have already learned how to configure xdebug to display values of superglobal variables. In addition, you can configure xdebug to display the current values of local variables as well. To display local variables along with every error message, you need to add

xdebug.show_local_vars=1

 

to php.ini. You can use ini_set as well, which we won‘t repeat mentioning from now on. Just keep in mind that you can do a lot of configuration at runtime, but you can obviously not change settings that affect work that is done before your script actually starts.

By the way, the php.ini settings xdebug.var_display_max_data, debug.var_display_max_children, and xdebug.var_display_max_depth that we used above to control the formatting of the var_dump() output also affect the format of variables that xdebug outputs in error messages. The same holds true for display of superglobals.

There is even more. With xdebug.collect_params, you can configure xdebug to display information about the parameters that were passed to a function. xdebug.collect_params takes a numeric parameter, with 0 meaning no additional information, and 4 meaning to display the variable name and always the full contents of each function parameter. A value of 3 will display name and parameter, but honoring the configuration settings mentioned above and thus truncating long variable content. A value of 1 will display the type and number of elements only, whereas 2 will in addition display the full information in a tooltip. Using a tooltip is very convenient for online viewing, but not really suitable for printing the information.

Here is the xdebug configuration used to create the following screenshot:

xdebug.show_local_vars=On
xdebug.dump.SERVER=HTTP_HOST, SERVER_NAME
xdebug.dump_globals=On
xdebug.collect_params=4

This screenshot was taken using the following xdebug configuration:

Please note that the more information you ask xdebug to collect during script execution, the more memory and computing time it will use, thus slowing the execution of your script. Make sure to only enable xdebug on development systems, and never on production systems. It is not a wise idea to display error messages as part of the HTML result on production systems, and it is even less of a good idea to enrich this information with stack traces and potentially variable values. Imagine your web site displaying your database username and password to everybody just because you use an uninitialized variable!

Since superglobal variables should not change at runtime, xdebug by default displays them only on the first error message, not in every error message. If you want xdebug to repeat dumping the global variables on every error, use

xdebug.dump_once=Off

Please note that the extended error display of xdebug does not work if you define a custom error handler using register_error_handler(). This is because xdebug internally uses the same mechanism. Should your scripts use a custom error handler, you can still use the function xdebug_get_function_stack() to output the stack trace in your custom error handler.

Object-oriented code uses exceptions when something goes wrong. Since an exception is not an error, xdebug will not display a stack trace when an exception is thrown, but only if that exception is uncaught. That is because an uncaught exception is a fatal error. To can configure xdebug to display a stack trace whenever an execption is thrown, use

xdebug.show_exception_trace=On

Recursion Limit

Another very useful feature is the fact that xdebug limits recursion depth, thus preventing endless recursion, which usually makes PHP segfault on Unix. On Windows, PHP even locks up the whole system when it falls into endless recursion, which is usually far worse than having PHP segfault.

xdebug prevents endless recursion by stopping the script once a pre-defined nesting depth is reached. This is, in effect, a limit of the stack size. Every recursive function call will increase the stack size, but also nested regular function calls increase the stack size. The default value is 100 and this feature is enabled by default. You can modify this limit, which might be necessary if you work with a script that works on deeply nested recursive data structures.

xdebug.max_nesting_level=<your preferred value>

Bear in mind, however, that xdebug does not prevent endless loops with for, while or similar, since they do not increase the stack size. You can easily put an additional counter into such loops, however, that just kills the script after a ridiculously high number of repetitions. I would not recommend doing this in production code, though, since a program can can never tell wether a loop is endless.

Conclusion

xdebug is a small, but very useful tool in PHP development. It should be installed and activated on every PHP installation that is used for development. You should not run xdebug on a production system, though, because most features degrade performance. Personally, I would never want to miss xdebug a single day on my development system, and if it is just for the better formatting of the var_dump() output.

Today, we have just scratched the surface of what xdebug can do to make your every day‘s life as a developer much easier. Next week, we will explore the tracing features of xdebug. Tracing helps you better understand your applications, and can be a replacement for putting loads of var_dump() statements into your code.

Make sure you check back here next week for the second part of this series of xdebug articles. Until then: Happy coding - with xdebug enabled.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。如发现有害或侵权内容,请点击这里 或 拨打24小时举报电话:4000070609 与我们联系。

    猜你喜欢

    0条评论

    发表

    请遵守用户 评论公约

    类似文章
    喜欢该文的人也喜欢 更多