Xdebug PHP 调试器的使用详解
假定经过简单的运行后,一个分层构造的 Web 应用程序 —— 包括客户机、网络、HTTP 服务器、应用程序代码和底层数据库 —— 将会很难隔离 PHP 代码中的错误。即使假定除了 PHP 代码以外所有层都可以正常运行,跟踪 PHP 代码中的错误也会非常难,尤其是在应用程序利用较多的类时更是如此。
PHP 语句 echo 和函数 var_dump()、debug_zval_dump() 和 print_r() 都是常见且流行的调试辅助工具,可以帮助解决多种问题。但是,这些语句 —— 甚至更健壮的工具,例如 PEAR Log package —— 都是取证工具,必须在上下文环境之外先进行推测分析才能生成证据。
在某种程度上,通过推论进行调试是一种蛮干的做法。收集并筛选数据,尝试推论出发生的问题。如果缺少重要信息,则必须重新测试代码、重复执行步骤,然后重新开始研究。一种更加高效的方法是在 程序运行时探测应用程序。您可以对请求参数分类,筛选过程调用堆栈,并查询任何所需的变量或对象。您可以暂时中断应用程序并且可以在变量更改值时收到警报。在某些情况下,您可以通过交互式询问 “如果……会怎样?” 问题来实际影响变量。
称为调试器 的特殊应用程序支持这种 “实时的” 或交互式的检查。调试器可能启动并连接到进程上以便控制进程并监测其内存。或者,在使用解释语言的情况下,调试器可以直接解释代码。典型的现代图形化调试器可以索引并浏览代码,以符合人类阅读习惯的形式轻松地显示复杂的数据结构,并同时显示程序状态,如调用堆栈、中间输出和所有变量的值。例如,调试器通常都会把类的属性和方法分类并进行描述。
在本文和下一篇文章中,我将介绍的工具一定能够简化 PHP 调试。下一次,我将主要介绍交互式调试和 Zend Debugger —— 一个特别针对 PHP 的健壮调试器 —— 并探究它提供的许多功能。(Zend Debugger 是一款商业产品,是 Zend PHP 集成开发环境(IDE)的一部分)。我还将介绍一款开源 PHP 调试器,以免您只愿把钱花在啤酒上,而不是花在代码上。但是,本文将主要介绍如何更好地取证。
类似《犯罪现场调查》,只是更令人讨厌
代码出错、未能生成某个所需结果或者彻底崩溃时,您需要回答四个 w 问题:where、what、why 和 when:
“where” 是应用程序最后一次正常运行时所在的文件和行号。
“what” 是犯错的代码 —— 比如说,嫌疑犯。
“why” 是错误的本质。可能它是一个逻辑错误和/或与操作系统进行交互所导致的错误,或两者兼具。
而 “when” 是出现错误时的上下文。在程序终止前发生了什么情况?像在所有犯罪行为中一样,如果您可以收集到足够的线索,那么线索就可以帮助您找到犯人。
一种取证工具 Xdebug(上一篇文章中使用的工具,用于分析 PHP 应用程序性能),如名称所示,将提供几个说明程序状态的功能,并且是应当添加到指令系统中的价值颇高的研究工具(请参阅 参考资料)。安装后,Xdebug 将阻止无限次递归(表面上是这样)、修正关于堆栈跟踪和函数跟踪的错误消息以及监视内存分配,并提供其他功能。Xdebug 还包括一组函数,您可以将这组函数添加到代码中以进行运行时错误诊断。
例如,下面的代码将使用一些 xdebug_...() 步骤测试 callee() 函数,以便输出调用程序的具体位置,包括文件名、行号和调用函数的名称。
清单 1. 测试 callee() 函数的步骤
function callee( $a ) {
echo sprintf("callee() called @ %s: %s from %s",
xdebug_call_file(),
xdebug_call_line(),
xdebug_call_function()
);
}
$result = callee( "arg" );
?>
这段代码将生成:
callee() called @ /var/www/catalog/xd.php: 10 from {main}
回页首构建和安装 Xdebug
Xdebug 可以很轻松地从 UNIX® 类操作系统(包括 Mac OS X)中的源代码构建。如果是在 Microsoft® Windows® 上使用 PHP,则可以从 Xdebug Web 站点下载最新 PHP 版本的二进制 Xdebug 模块(请参阅 参考资料)。
让我们来构建和安装适用于 Debian “Sarge” Linux® 和 PHP V4.3.10-19 的 Xdebug。在撰写本文时,Xdebug 的最新版本是 V2.0.0RC4,发布于 2007 年 5 月 17 日。要继续本文,必须拥有 phpize 和 php-config 实用程序,并且必须能够编辑系统的 php.ini 配置文件(如果没有实用程序,请访问 PHP.net 以获得如何从头构建 PHP 的源代码和说明)。请执行以下步骤:
下载 Xdebug tarball(一个用 gzip 压缩的 .tar 归档文件)。wget 命令可以帮助您轻松地完成此操作: $ wget http://www.xdebug.org/files/xdebug-2.0.0RC4.tgz
解压缩该 tarball 并切换到源代码目录:$ tar xzf xdebug-2.0.0RC4.tgz
$ cd xdebug-2.0.0RC4
运行 phpize 以准备适用于您的 PHP 版本的 Xdebug 代码:$ phpize
Configuring for:
PHP Api Version: 20020918
Zend Module Api No: 20020429
Zend Extension Api No: 20021010
phpize 的输出是一个脚本 —— 通常名为配置 —— 用于调整其余的构建过程。
运行配置脚本:$ ./configure
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
...
checking whether stripping libraries is possible... yes
appending configuration tag "F77" to libtool
configure: creating ./config.status
config.status: creating config.h
通过运行 make 构建 Xdebug 扩展:$ make
/bin/sh /home/strike/tmp/xdebug-2.0.0RC4/libtool
--mode=compile gcc -I.
-I/home/strike/tmp/xdebug-2.0.0RC4 -DPHP_ATOM_INC
-I/home/strike/tmp/xdebug-2.0.0RC4/include
-I/home/strike/tmp/xdebug-2.0.0RC4/main
-I/home/strike/tmp/xdebug-2.0.0RC4
-I/usr/include/php4 -I/usr/include/php4/main
-I/usr/include/php4/Zend -I/usr/include/php4/TSRM
-DHAVE_CONFIG_H -g -O0 -c
/home/strike/tmp/xdebug-2.0.0RC4/xdebug.c -o
xdebug.lo mkdir .libs
...
Build complete.
(It is safe to ignore warnings about tempnam and tmpnam).
使用 make 将生成 Xdebug 扩展 xdebug.so。
安装该扩展:$ sudo make install
Installing shared extensions: /usr/lib/php4/20020429/
继续之前,使用鼠标选择并复制上一条命令显示的目录。该路径对于最后一步配置扩展至关重要。
在您喜欢的文本编辑器中打开 php.ini 文件,然后添加以下代码:zend_extension = /usr/lib/php4/20020429/xdebug.so
xdebug.profiler_enable = Off
xdebug.default_enable = On
第一行将装入 Xdebug 扩展;第二行将禁用 Xdebug 的分析器功能(只是为了简单起见),而第三行将启用扩展的调试功能。
要检验 Xdebug 扩展是否已经安装并启用,请重新启动 Web 服务器,然后用代码 创建简单的一行 PHP 应用程序。如果将浏览器指向文件 —— 如 http://localhost/phpinfo.php —— 并向下滚动,您应当会看到类似图 1 所示的内容。
图 1. 检验 Xdebug 扩展是否已经安装并运行
注:如果您在 phpinfo() 的输出中没有看到 Xdebug 部分,则 Xdebug 装入失败。Apache 错误日志会列出原因。常见错误包括zend_extension 的路径错误或者与其他扩展发生冲突。例如,如果需要使用 XCache 和 Xdebug,一定要先装入 XCache。但是,由于 Xdebug 适于在开发时使用并假定 xdebug.so 的路径正确,因此需要禁用其他扩展并重试。然后您可以重新启用扩展以执行其他测试,如缓存的效果。Xdebug 站点还有其他一些故障检修技巧。