如何调试PHP脚本?
我知道基本的调试,如使用错误报告。PHPEclipse中的断点调试也非常有用。
在phpStorm或任何其他IDE中调试的最佳方法(就快速和简单而言)是什么?
如何调试PHP脚本?
我知道基本的调试,如使用错误报告。PHPEclipse中的断点调试也非常有用。
在phpStorm或任何其他IDE中调试的最佳方法(就快速和简单而言)是什么?
尝试Eclipse PDT来设置具有您提到的调试特性的Eclipse环境。与var_dump的老方法相比,进入代码的能力是一种更好的调试方法,并在各个点打印,以查看流在哪里出错。当所有这些都失败了,虽然,我只有SSH和vim,我仍然var_dump()/die()找到哪里的代码出错。
由Derick Rethans编写的Xdebug非常好。我前段时间用过,发现安装起来不那么容易。一旦你完成了,你就不会明白没有它你是如何做到的:-)
在Zend开发者专区有一篇很好的文章(在Linux上安装似乎并不容易),甚至还有一个Firefox插件,我从来没用过。
坦率地说,是print和print_r()的组合,以打印出变量。我知道很多人更喜欢使用其他更高级的方法,但我发现这是最容易使用的。
我要说的是,直到我在Uni做了一些微处理器编程,甚至都不会使用它,我才完全理解这一点。
print_r() +1。使用它来转储对象或变量的内容。为了使它更具可读性,使用pre标记,这样你就不需要查看源代码了。
echo '<pre>';
print_r($arrayOrObject);
还有var_dump($thing) -这对于查看子事物的类型非常有用
根据问题的不同,我喜欢将error_reporting(E_ALL)与echo测试混合使用(以找到最初发生错误的违规行/文件;你知道它并不总是行/文件php告诉你对吗?),IDE大括号匹配(解决“解析错误:语法错误,意外的$end”问题),和print_r();退出;转储(真正的程序员查看源代码;p)。
你也不能用“memory_get_usage();”和“memory_get_peak_usage();”来打败phpdebug(检查sourceforge)来找到问题区域。
1)使用print_r()。在TextMate中,我有一个'pre'的片段,它扩展为:
echo "<pre>";
print_r();
echo "</pre>";
2)我使用Xdebug,但还不能让GUI在我的Mac上正常工作。它至少打印出一个可读的堆栈跟踪版本。
我使用内置调试器的zend studio for eclipse。与使用eclipse pdt和xdebug进行调试相比,它仍然很慢。希望他们能解决这些问题,在最近的版本中,速度有所提高,但仍然需要2-3秒。 zend firefox工具栏让事情变得非常简单(调试下一页、当前页等)。此外,它还提供了一个分析器,可以对代码进行基准测试,并提供饼状图、执行时间等。
For the really gritty problems that would be too time consuming to use print_r/echo to figure out I use my IDE's (PhpEd) debugging feature. Unlike other IDEs I've used, PhpEd requires pretty much no setup. the only reason I don't use it for any problems I encounter is that it's painfully slow. I'm not sure that slowness is specific to PhpEd or any php debugger. PhpEd is not free but I believe it uses one of the open-source debuggers (like XDebug previously mentioned) anyway. The benefit with PhpEd, again, is that it requires no setup which I have found really pretty tedious in the past.
XDebug对于开发至关重要。我安装它之前任何其他扩展。它为您提供任何错误的堆栈跟踪,您可以轻松地启用分析。
使用var_dump()可以快速查看数据结构。不要使用print_r(),因为你必须用<pre>包围它,而且它一次只打印一个var。
<?php var_dump(__FILE__, __LINE__, $_REQUEST); ?>
对于一个真正的调试环境,我发现最好的是Komodo IDE,但它要花费$$。
Komodo IDE works well with xdebug, even for the remore debugging. It needs minimum amount of configuration. All you need is a version of php that Komodo can use locally to step through the code on a breakpoint. If you have the script imported into komodo project, then you can set breakpoints with a mouse-click just how you would set it inside eclipse for debugging a java program. Remote debugging is obviously more tricky to get it to work correctly ( you might have to map the remote url with a php script in your workspace ) than a local debugging setup which is pretty easy to configure if you are on a MAC or a linux desktop.
集成的调试器,可以在逐步执行代码时观察变量值的变化,这真的很酷。但是,它们确实需要在服务器上安装软件,并在客户机上进行一定数量的配置。两者都需要定期维护以保持良好的工作状态。
print_r易于编写,并保证在任何设置中都能工作。
在某种程度上,这取决于事情的走向。这是我尝试分离的第一件事,然后在必要时使用echo/print_r()。
注:你们知道你可以把true作为第二个参数传递给print_r(),它会返回输出而不是打印它吗?例如:
echo "<pre>".print_r($var, true)."</pre>";
通常我发现创建一个自定义日志功能可以保存在文件中,存储调试信息,并最终在公共页脚上重新打印。
您还可以重写常见的Exception类,以便这种类型的调试是半自动化的。
如果您不想弄乱输出,输出缓冲是非常有用的。我在一行代码中做到了这一点,我可以随意注释/取消注释
ob_start();var_dump(); user_error(ob_get_contents()); ob_get_clean();
这是我的调试环境:
error_reporting(-1);
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_BAIL, 0);
assert_options(ASSERT_QUIET_EVAL, 0);
assert_options(ASSERT_CALLBACK, 'assert_callcack');
set_error_handler('error_handler');
set_exception_handler('exception_handler');
register_shutdown_function('shutdown_handler');
function assert_callcack($file, $line, $message) {
throw new Customizable_Exception($message, null, $file, $line);
}
function error_handler($errno, $error, $file, $line, $vars) {
if ($errno === 0 || ($errno & error_reporting()) === 0) {
return;
}
throw new Customizable_Exception($error, $errno, $file, $line);
}
function exception_handler(Exception $e) {
// Do what ever!
echo '<pre>', print_r($e, true), '</pre>';
exit;
}
function shutdown_handler() {
try {
if (null !== $error = error_get_last()) {
throw new Customizable_Exception($error['message'], $error['type'], $error['file'], $error['line']);
}
} catch (Exception $e) {
exception_handler($e);
}
}
class Customizable_Exception extends Exception {
public function __construct($message = null, $code = null, $file = null, $line = null) {
if ($code === null) {
parent::__construct($message);
} else {
parent::__construct($message, $code);
}
if ($file !== null) {
$this->file = $file;
}
if ($line !== null) {
$this->line = $line;
}
}
}
通过简单地var_dump一些关键变量,可以很容易地找到大多数错误,但这显然取决于您开发的应用程序类型。
对于更复杂的算法,步进/断点/观察函数是非常有用的(如果没有必要)
当不能使用Rails时,我经常使用CakePHP。为了调试错误,我通常会在tmp文件夹中找到error.log,然后在终端中使用命令…
tail -f app/tmp/logs/error.log
它可以让你从蛋糕中运行正在发生的事情的对话框,这非常方便,如果你想在代码中输出一些东西,你可以使用。
$this->log('xxxx');
这通常可以让你很好地了解发生了什么。
我使用Netbeans的XDebug和Easy XDebug FireFox插件
The add-on is essential when you debug MVC projects, because the normal way XDebug runs in Netbeans is to register the dbug session via the url. With the add-on installed in FireFox, you would set your Netbeans project properties -> Run Configuratuion -> Advanced and select "Do Not Open Web Browser" You can now set your break points and start the debugging session with Ctrl-F5 as usual. Open FireFox and right-click the Add-on icon in the right bottom corner to start monitoring for breakpoints. When the code reaches the breakpoint it will stop and you can inspect your variable states and call-stack.
有许多PHP调试技术可以在编码时节省无数的时间。一个有效但基本的调试技术是简单地打开错误报告。另一种稍微高级一点的技术涉及到使用print语句,它可以通过在屏幕上显示实际发生的内容来帮助查明更难以捉摸的错误。PHPeclipse是一个Eclipse插件,可以突出显示常见的语法错误,并且可以与调试器一起使用来设置断点。
display_errors = Off
error_reporting = E_ALL
display_errors = On
也用过
error_log();
console_log();
PHP DBG
交互式逐步PHP调试器实现为一个SAPI模块,它可以让你完全控制环境,而不影响代码的功能或性能。它的目标是成为一个轻量级、功能强大、易于使用的PHP 5.4+调试平台,它随PHP 5.6一起发布。
功能包括:
Stepthrough调试 灵活的断点(类方法,函数,文件:行,地址,操作码) 使用内置eval()轻松访问PHP 轻松访问当前正在执行的代码 用户态的API SAPI不可知论-易于集成 PHP配置文件支持 JIT超级全球赛-设置你自己!! 可选readline支持-舒适的终端操作 远程调试支持-绑定的Java GUI 操作简单
请看截图:
首页:http://phpdbg.com/
PHP错误-更好的PHP错误报告
这是非常容易使用库(实际上是一个文件)来调试PHP脚本。
你需要做的唯一一件事就是包括一个文件,如下所示(在你的代码的开头):
require('php_error.php');
\php_error\reportErrors();
然后所有的错误都会给你一些信息,比如回溯、代码上下文、函数参数、服务器变量等等。例如:
功能包括:
trivial to use, it's just one file errors displayed in the browser for normal and ajaxy requests AJAX requests are paused, allowing you to automatically re-run them makes errors as strict as possible (encourages code quality, and tends to improve performance) code snippets across the whole stack trace provides more information (such as full function signatures) fixes some error messages which are just plain wrong syntax highlighting looks pretty! customization manually turn it on and off run specific sections without error reporting ignore files allowing you to avoid highlighting code in your stack trace application files; these are prioritized when an error strikes!
首页:http://phperror.net/
GitHub: https://github.com/JosephLenton/PHP-Error
我的叉子(有额外的修复):https://github.com/kenorb-contrib/PHP-Error
DTrace
如果您的系统支持DTrace动态跟踪(在OS X上默认安装),并且您的PHP编译时启用了DTrace探测(——enable-dtrace),这应该是默认的,这个命令可以帮助您在没有时间的情况下调试PHP脚本:
sudo dtrace -qn 'php*:::function-entry { printf("%Y: PHP function-entry:\t%s%s%s() in %s:%d\n", walltimestamp, copyinstr(arg3), copyinstr(arg4), copyinstr(arg0), basename(copyinstr(arg1)), (int)arg2); }'
因此,给定以下别名已添加到您的rc文件中(例如~/。bashrc, (~ / .bash_aliases):
alias trace-php='sudo dtrace -qn "php*:::function-entry { printf(\"%Y: PHP function-entry:\t%s%s%s() in %s:%d\n\", walltimestamp, copyinstr(arg3), copyinstr(arg4), copyinstr(arg0), basename(copyinstr(arg1)), (int)arg2); }"'
您可以使用易于记忆的别名跟踪脚本:trace-php。
这里是更高级的dtrace脚本,只需将其保存到dtruss-php。D,使其可执行(chmod +x dtruss-php.d),并运行:
#!/usr/sbin/dtrace -Zs
# See: https://github.com/kenorb/dtruss-lamp/blob/master/dtruss-php.d
#pragma D option quiet
php*:::compile-file-entry
{
printf("%Y: PHP compile-file-entry:\t%s (%s)\n", walltimestamp, basename(copyinstr(arg0)), copyinstr(arg1));
}
php*:::compile-file-return
{
printf("%Y: PHP compile-file-return:\t%s (%s)\n", walltimestamp, basename(copyinstr(arg0)), basename(copyinstr(arg1)));
}
php*:::error
{
printf("%Y: PHP error message:\t%s in %s:%d\n", walltimestamp, copyinstr(arg0), basename(copyinstr(arg1)), (int)arg2);
}
php*:::exception-caught
{
printf("%Y: PHP exception-caught:\t%s\n", walltimestamp, copyinstr(arg0));
}
php*:::exception-thrown
{
printf("%Y: PHP exception-thrown:\t%s\n", walltimestamp, copyinstr(arg0));
}
php*:::execute-entry
{
printf("%Y: PHP execute-entry:\t%s:%d\n", walltimestamp, basename(copyinstr(arg0)), (int)arg1);
}
php*:::execute-return
{
printf("%Y: PHP execute-return:\t%s:%d\n", walltimestamp, basename(copyinstr(arg0)), (int)arg1);
}
php*:::function-entry
{
printf("%Y: PHP function-entry:\t%s%s%s() in %s:%d\n", walltimestamp, copyinstr(arg3), copyinstr(arg4), copyinstr(arg0), basename(copyinstr(arg1)), (int)arg2);
}
php*:::function-return
{
printf("%Y: PHP function-return:\t%s%s%s() in %s:%d\n", walltimestamp, copyinstr(arg3), copyinstr(arg4), copyinstr(arg0), basename(copyinstr(arg1)), (int)arg2);
}
php*:::request-shutdown
{
printf("%Y: PHP request-shutdown:\t%s at %s via %s\n", walltimestamp, basename(copyinstr(arg0)), copyinstr(arg1), copyinstr(arg2));
}
php*:::request-startup
{
printf("%Y, PHP request-startup:\t%s at %s via %s\n", walltimestamp, basename(copyinstr(arg0)), copyinstr(arg1), copyinstr(arg2));
}
主页:GitHub的dtruss-lamp
下面是简单的用法:
执行命令sudo dtruss-php.d。 在另一个终端运行:php -r "phpinfo();"。
为了测试这一点,你可以使用index.php找到任何docroot,并通过以下方式运行PHP内置服务器:
php -S localhost:8080
之后,您可以通过http://localhost:8080/访问该网站(或选择任何对您方便的端口)。从那里访问一些页面以查看跟踪输出。
注意:Dtrace默认在OS X上可用,在Linux上你可能需要dtrace4linux或检查一些其他替代方案。
参见:在php.net上使用PHP和DTrace
SystemTap
或者通过安装SystemTap SDT开发包来检查SystemTap跟踪(例如yum install SystemTap - SDT -devel)。
下面是一个示例脚本(all_probes.stp),用于在SystemTap运行的PHP脚本期间跟踪所有核心PHP静态探测点:
probe process("sapi/cli/php").provider("php").mark("compile__file__entry") {
printf("Probe compile__file__entry\n");
printf(" compile_file %s\n", user_string($arg1));
printf(" compile_file_translated %s\n", user_string($arg2));
}
probe process("sapi/cli/php").provider("php").mark("compile__file__return") {
printf("Probe compile__file__return\n");
printf(" compile_file %s\n", user_string($arg1));
printf(" compile_file_translated %s\n", user_string($arg2));
}
probe process("sapi/cli/php").provider("php").mark("error") {
printf("Probe error\n");
printf(" errormsg %s\n", user_string($arg1));
printf(" request_file %s\n", user_string($arg2));
printf(" lineno %d\n", $arg3);
}
probe process("sapi/cli/php").provider("php").mark("exception__caught") {
printf("Probe exception__caught\n");
printf(" classname %s\n", user_string($arg1));
}
probe process("sapi/cli/php").provider("php").mark("exception__thrown") {
printf("Probe exception__thrown\n");
printf(" classname %s\n", user_string($arg1));
}
probe process("sapi/cli/php").provider("php").mark("execute__entry") {
printf("Probe execute__entry\n");
printf(" request_file %s\n", user_string($arg1));
printf(" lineno %d\n", $arg2);
}
probe process("sapi/cli/php").provider("php").mark("execute__return") {
printf("Probe execute__return\n");
printf(" request_file %s\n", user_string($arg1));
printf(" lineno %d\n", $arg2);
}
probe process("sapi/cli/php").provider("php").mark("function__entry") {
printf("Probe function__entry\n");
printf(" function_name %s\n", user_string($arg1));
printf(" request_file %s\n", user_string($arg2));
printf(" lineno %d\n", $arg3);
printf(" classname %s\n", user_string($arg4));
printf(" scope %s\n", user_string($arg5));
}
probe process("sapi/cli/php").provider("php").mark("function__return") {
printf("Probe function__return: %s\n", user_string($arg1));
printf(" function_name %s\n", user_string($arg1));
printf(" request_file %s\n", user_string($arg2));
printf(" lineno %d\n", $arg3);
printf(" classname %s\n", user_string($arg4));
printf(" scope %s\n", user_string($arg5));
}
probe process("sapi/cli/php").provider("php").mark("request__shutdown") {
printf("Probe request__shutdown\n");
printf(" file %s\n", user_string($arg1));
printf(" request_uri %s\n", user_string($arg2));
printf(" request_method %s\n", user_string($arg3));
}
probe process("sapi/cli/php").provider("php").mark("request__startup") {
printf("Probe request__startup\n");
printf(" file %s\n", user_string($arg1));
printf(" request_uri %s\n", user_string($arg2));
printf(" request_method %s\n", user_string($arg3));
}
用法:
stap -c 'sapi/cli/php test.php' all_probes.stp
参见:在php.net上使用SystemTap和PHP DTrace静态探针