有些时候,当你运行一个php脚本时,你可能想知道这个脚本到底在捣鼓什么。有些工具可以帮助你不停脚本弄清楚它。这些工具有些只能再linux上工作。
gdb-the gnu debugger-是一个C/C++程序debugger。而且它提供了和Xdebug一样的php脚本debug功能。你可以将php脚本作为gdb的参数,然后在gdb命令行中输入run:
或者讲一个已经运行的进程作为参数,执行cont
一旦脚本运行到某个你感兴趣的状态想知道它到底在干什么,你可以ctrl-c. 这样你可以返回(gdb)提示符,然后可以输入运行bt得到php正在调用的C语言函数。例如:
为了弄清正在运行那个php函数,bt略微有点无力。对于每个内部函数和方法,你可以看到函数以zip_和zim_开头。但是用户定义函数只有一个执行函数列表。但是这样你也可以弄清楚哪个用户定义函数正在被运行。顺便说一下.gdbinit脚本。
这个脚本是php资源分布的一部分,处于资源树的最高级。因为我想加载这个文件,我必须拷贝这个文件到自己的主目录。gdb在其开始载入该文件,但是如果你想在特定脚本下载入该文件,你可以再(gdb)提示符:
如果随着脚本载入可以再(gdb)提示符下:
执行zbacktrace,结果如下:
zz from: http://derickrethans.nl/what-is-php-doing.html
stace
第一个工具是stace。stace是一个可以追踪系统调用的工具。系统调用主要是php读写网络端口或者文件;也包括通过网络和域套接字读写数据库。strace也会显示其他的系统调用比如time。stace的使用方法:strace -p <processid>
processid可以通过先执行
ps aux|grep php
,然后根绝cpu利用率等信息来猜。也可以直接将程序作为strace的参数运行
strace php yourscript.php
你可以限定输出只特定的系统调用。使用如下命令讲只显示open和close系统调用。
strace -e open,close php yourscript.php
如果yourscript.php不存在,最后调用的输出如下:
...
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY) = 3
close(3) = 0
open("/etc/services", O_RDONLY|O_CLOEXEC) = 3
close(3) = 0
open("/sys/devices/system/cpu", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
close(3) = 0
open("yourscript.php", O_RDONLY) = -1 ENOENT (No such file or directory)
Could not open input file: yourscript.php
这个命令也有助于确定载入的是哪个php.ini
strace -e open php yourscript.php 2>&1 | grep php.ini
因为可能需要去stderr中提取信息,因此把stderr重定向到stdout
ltrace
ltrace的运行和使用与strace一样,它也能告诉你哪个内部库函数被调用了。它提供了更多的信息,但是它应该描述的更清楚点到底哪个C-library函数被调用,因此不如strace有用。gdb
如果strace和ltrace都不能得到任何输出,可能你的脚本或者扩展正在做大量的计算。为了弄清楚到底哪个php函数被调用,你可以使用gdb工具。gdb-the gnu debugger-是一个C/C++程序debugger。而且它提供了和Xdebug一样的php脚本debug功能。你可以将php脚本作为gdb的参数,然后在gdb命令行中输入run:
gdb --args php yourscript.php
(gdb) run
或者讲一个已经运行的进程作为参数,执行cont
gdb -p <processid>
(gdb) cont
一旦脚本运行到某个你感兴趣的状态想知道它到底在干什么,你可以ctrl-c. 这样你可以返回(gdb)提示符,然后可以输入运行bt得到php正在调用的C语言函数。例如:
^C
Program received signal SIGINT, Interrupt.
xdebug_execute (op_array=0x1f03b00)
at /home/derick/dev/php/xdebug/xdebug.c:1409
1409 zval_ptr_dtor(EG(return_value_ptr_ptr));
(gdb) bt
#0 xdebug_execute (op_array=0x1f03b00)
at /home/derick/dev/php/xdebug/xdebug.c:1409
#1 0x000000000099d9a2 in zend_do_fcall_common_helper_SPEC (
execute_data=0x7f3dec906090)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/Zend/zend_vm_execute.h:344
#2 0x00000000009a1cb7 in ZEND_DO_FCALL_SPEC_CONST_HANDLER (
execute_data=0x7f3dec906090)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/Zend/zend_vm_execute.h:1640
#3 0x000000000099cce7 in execute (op_array=0x1ee2d50)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/Zend/zend_vm_execute.h:107
#4 0x00007f3de53debfe in xdebug_execute (op_array=0x1ee2d50)
at /home/derick/dev/php/xdebug/xdebug.c:1391
#5 0x00000000009696a8 in zend_execute_scripts (type=8, retval=0x0,
file_count=3)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/Zend/zend.c:1236
#6 0x00000000008f296d in php_execute_script (primary_file=0x7fff9ad6d8b0)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/main/main.c:2308
#7 0x0000000000a4b8b3 in main (argc=2, argv=0x7fff9ad6db48)
at /home/derick/dev/php/php-src-git/branches/PHP_5_3/sapi/cli/php_cli.c:1189
为了弄清正在运行那个php函数,bt略微有点无力。对于每个内部函数和方法,你可以看到函数以zip_和zim_开头。但是用户定义函数只有一个执行函数列表。但是这样你也可以弄清楚哪个用户定义函数正在被运行。顺便说一下.gdbinit脚本。
这个脚本是php资源分布的一部分,处于资源树的最高级。因为我想加载这个文件,我必须拷贝这个文件到自己的主目录。gdb在其开始载入该文件,但是如果你想在特定脚本下载入该文件,你可以再(gdb)提示符:
(gdb) source /home/derick/dev/php/PHP_5_3/.gdbinit
如果随着脚本载入可以再(gdb)提示符下:
(gdb) zbacktrace
一下面这个脚本举例:
<?php
function addOne( &$i )
{
$i++;
}
$i = 0;
while (true) {
addOne( $i );
}
?>
执行zbacktrace,结果如下:
(gdb) zbacktrace
[0xec906090] addOne() /tmp/yourscript.php:9
zz from: http://derickrethans.nl/what-is-php-doing.html