如何调试PHP脚本?

如何调试PHP脚本?

我知道基本的调试,如使用错误报告。PHPEclipse中的断点调试也非常有用。

在phpStorm或任何其他IDE中调试最好的(就快速和简单而言)的方法是什么?

355290 次浏览

我使用了Zend Studio (5.5)Zend平台。这就提供了适当的调试、断点/跨代码等,尽管是有代价的。

尝试Eclipse PDT来设置一个Eclipse环境,该环境具有您提到的调试功能。与var_dump的老方法相比,进入代码的能力是一种更好的调试方法,并在各个点打印,以查看流在哪里出错。当所有这些都失败了,尽管我只有SSH和vim,我仍然var_dump()/die()找到代码出错的地方。

Print_r (debug_backtrace());

或者类似的东西:-)

Xdebug,由Derick Rethans,是非常好的。我前段时间用过,发现安装起来不那么容易。一旦你完成了,你就不会明白没有它你是如何做到的:-)

有一篇关于Zend开发者区的好文章(在Linux上安装似乎并不容易),甚至还有一篇我从未使用过的火狐浏览器插件

坦率地说,是print和print_r()的组合,以打印出变量。我知道很多人更喜欢使用其他更高级的方法,但我发现这是最容易使用的。

我要说的是,直到我在Uni做了一些微处理器编程,甚至都不会使用它,我才完全理解这一点。

print_r() +1。使用它来转储对象或变量的内容。为了使它更具可读性,使用pre标记,这样你就不需要查看源代码了。

echo '<pre>';
print_r($arrayOrObject);

还有var_dump($thing) -这对于查看子事物的类型非常有用

您可以使用Firephp作为firebug的附加组件在与javascript相同的环境中调试php。

我还使用前面提到的Xdebug来分析php。

根据问题的不同,我喜欢将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上正常工作。它至少打印出一个可读的堆栈跟踪版本。

在生产环境中,我使用error_log()将相关数据记录到服务器的错误日志中。

我使用zend studio为eclipse内置调试器。与使用eclipse pdt和xdebug进行调试相比,它仍然很慢。希望他们能解决这些问题,在最近的版本中,速度有所提高,但仍然需要2-3秒。 zend firefox工具栏让事情变得非常简单(调试下一页、当前页等)。此外,它还提供了一个分析器,可以对代码进行基准测试,并提供饼图、执行时间等

对于真正棘手的问题,使用print_r/echo来解决太浪费时间,我使用我的IDE的(PhpEd)调试特性。与我使用过的其他ide不同,PhpEd几乎不需要设置。我不使用它的唯一原因是我遇到的任何问题是痛苦的慢。我不确定缓慢是特定于PhpEd或任何php调试器。PhpEd不是免费的,但我相信它使用了一种开源调试器(如前面提到的XDebug)。PhpEd的好处是,它不需要设置,这在过去我发现非常乏味。

手动调试对我来说通常更快——var_dump()debug_print_backtrace()是你需要武装你的逻辑的所有工具。

XDebug对于开发是必不可少的。我安装它之前任何其他扩展。它为您提供任何错误的堆栈跟踪,您可以轻松地启用分析。

要快速查看数据结构,请使用var_dump()。不要使用print_r(),因为你必须用<pre>包围它,而且它一次只打印一个var。

<?php var_dump(__FILE__, __LINE__, $_REQUEST); ?>

对于一个真正的调试环境,我发现最好的是科摩多IDE,但它花费$$。

Komodo IDE与xdebug一起工作得很好,甚至用于更多的调试。它需要最少的配置。您所需要的只是一个php版本,Komodo可以在本地使用该版本逐级遍历断点上的代码。如果您将脚本导入到komodo项目中,那么您可以通过单击鼠标来设置断点,就像在eclipse中为调试java程序设置断点一样。 远程调试显然比本地调试要复杂得多(你可能需要在你的工作空间中用php脚本映射远程url),如果你是在MAC或linux桌面上,本地调试设置很容易配置

集成的调试器,可以在逐步执行代码时观察变量值的变化,这真的很酷。但是,它们确实需要在服务器上安装软件,并在客户机上进行一定数量的配置。两者都需要定期维护以保持良好的工作状态。

print_r易于编写,并保证在任何设置中都能工作。

我使用Netbeans与XDebug。 在它的网站上查看如何配置它的文档。 http://php.netbeans.org/ < / p >

Xdebug和用于notepad++的DBGp插件用于繁重的bug查找,FirePHP用于轻量级的东西。又快又脏?没有什么比dBug更好的了。

PhpEdit有一个内置调试器,但我通常最终使用echo();和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();

PhpEd真的很好。你可以进入/进入/退出函数。你可以运行特别代码,检查变量,改变变量。太神奇了。

这是我的调试环境:

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_dumping一些关键变量轻松找到,但这显然取决于你开发的应用程序类型。

对于更复杂的算法,步进/断点/观察函数是非常有用的(如果没有必要)

当不能使用Rails时,我经常使用CakePHP。为了调试错误,我通常在tmp文件夹中找到error.log,并在终端中使用命令…

tail -f app/tmp/logs/error.log

它可以让你从蛋糕中运行正在发生的事情的对话框,这非常方便,如果你想在代码中输出一些东西,你可以使用。

$this->log('xxxx');

这通常可以让你很好地了解发生了什么。

我使用Netbeans与XDebug和轻松XDebug FireFox插件

当您调试MVC项目时,这个附加组件是必不可少的,因为XDebug在Netbeans中运行的正常方式是通过url注册dbug会话。随着插件安装在FireFox中,您将设置您的Netbeans项目属性->运行配置->高级,并选择“不打开Web浏览器”。现在您可以设置断点,并像往常一样使用Ctrl-F5启动调试会话。打开FireFox,右键单击右下角的Add-on图标,开始监视断点。当代码到达断点时,它将停止,您可以检查变量状态和调用堆栈。

Nusphere也是一个很好的php调试器 nusphere < / p >

有许多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
  • 操作简单

请看截图:

PHP DBG - Stepthrough Debugging -截图 .

PHP DBG - Stepthrough Debugging -截图 .

首页:http://phpdbg.com/

PHP的错误 -更好的PHP错误报告

这是非常容易使用库(实际上是一个文件)来调试PHP脚本。

你需要做的唯一一件事就是包括一个文件,如下所示(在你的代码的开头):

require('php_error.php');
\php_error\reportErrors();

然后所有的错误都会给你一些信息,比如回溯、代码上下文、函数参数、服务器变量等等。例如:

PHP Error |改进PHP错误报告- backtrace的截图 PHP Error | Improve Error Reporting for PHP -截图of backtrace PHP Error |改进PHP错误报告- backtrace的截图 < / p >

功能包括:

  • 使用起来很简单,它只是一个文件
  • 正常和ajax请求在浏览器中显示的错误
  • AJAX请求被暂停,允许您自动重新运行它们
  • 使错误尽可能严格(鼓励代码质量,并倾向于提高性能)
  • 整个堆栈跟踪的代码片段
  • 提供更多信息(例如完整的函数签名)
  • 修复了一些完全错误的错误消息
  • 语法高亮显示
  • 看起来漂亮!
  • 定制
  • 手动打开和关闭
  • 运行特定的部分而不报告错误
  • 忽略允许您避免在堆栈跟踪中突出显示代码的文件
  • 应用程序文件;当出现错误时,这些是优先级!

首页:http://phperror.net/

GitHub: https://github.com/JosephLenton/PHP-Error

我的fork(有额外的修复):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); }'

因此,给定以下别名已添加到您的钢筋混凝土文件(例如~/.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));
}

主页:dtruss-lamp at GitHub

下面是简单的用法:

  1. 运行:sudo dtruss-php.d
  2. 在另一个终端上运行:php -r "phpinfo();"

为了测试这一点,你可以使用index.php到任何docroot,并通过以下方式运行PHP内置服务器:

php -S localhost:8080

之后,你可以通过http://localhost:8080/访问站点(或选择任何对你方便的端口)。从那里访问一些页面以查看跟踪输出。

注意:Dtrace默认在OS X上可用,在Linux上你可能需要dtrace4linux或检查一些其他的选择

参见:使用PHP和DTrace at php.net


SystemTap

或者通过安装SystemTap SDT开发包(例如yum install systemtap-sdt-devel)来检查SystemTap跟踪。

下面是一个示例脚本(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

参见:使用SystemTap和PHP DTrace静态探针 at php.net