【问题标题】:How do you debug PHP scripts? [closed]你如何调试 PHP 脚本? [关闭]
【发布时间】:2022-01-01 06:45:57
【问题描述】:

您如何调试 PHP 脚本?

我了解基本调试,例如使用错误报告。 PHPEclipse中的断点调试也很有用。

在 phpStorm 或任何其他 IDE 中进行调试的最佳(就快速简便而言)方法是什么?

【问题讨论】:

标签: php eclipse debugging phpstorm xdebug


【解决方案1】:

尝试Eclipse PDT 设置具有您提到的调试功能的 Eclipse 环境。与旧的 var_dump 方法相比,单步执行代码的能力是一种更好的调试方法,并在各个点打印以查看您的流程出错的地方。当所有其他方法都失败并且我只有 SSH 和 vim 时,我仍然 var_dump()/die() 来查找代码往南的地方。

【讨论】:

  • 你应该使用这个函数: kill( $data ) { die( var_dump ( $data ) );它节省了输入 10 个字符,这是我写过的最好的功能 tbh:)
  • 有没有办法美化“var_dump”?
  • @AlexMorley-Finch 我把你升到kill($data) { echo "<pre>"; var_dump($data); echo "</pre>"; exit; }
  • 链接可通过令人难以置信的Web Archive“恢复”,最后一次检查截至 2015 年 5 月 7 日。
【解决方案2】:

您可以使用 Firephp 一个插件到 firebug 来在与 javascript 相同的环境中调试 php。

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

【讨论】:

【解决方案3】:

这是我的小调试环境:

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;
        }
    }
}

【讨论】:

  • 谢谢。这拯救了我的一天。 (我只需要删除那个 E_STRICT)
  • assert_callcack呵呵
【解决方案4】:

Xdebug 和用于 Notepad++ 的 DBGp 插件用于重型错误搜索,FirePHP 用于轻量级的东西。又快又脏?没有什么能比得上dBug

【讨论】:

  • DBGp 插件不适用于当前版本的 notepad++/xdebug,并且没有修复它的计划。你可以看到我与创建者的讨论链接here
【解决方案5】:

XDebug 对开发至关重要。我在任何其他扩展之前安装它。它为您提供任何错误的堆栈跟踪,并且您可以轻松启用分析。

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

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

对于真正的调试环境,我发现最好的是Komodo IDE,但它的成本是 $$。

【讨论】:

    【解决方案6】:

    PhpEd 真的很好。您可以进入/结束/退出功能。您可以运行临时代码、检查变量、更改变量。太棒了。

    【讨论】:

    • 我使用过 PhpEd,与 NetBeans 或 Eclipse 等真正的 IDE 相比,我没有任何好话,这条评论也没有为这个问题添加任何有用的信息。 -1
    • 在购买 PhpED Professional 之前,我尝试了大多数 IDE(包括 Zend、NetBeans 和 Eclipse),因为它是最好的。这是几年前的事了,所以其他的可能已经改进了,但当时它们中的大多数都非常缓慢,因为它们是用 Java 编写的。我不明白当(对我而言)这显然是最好的,这个决定是不费吹灰之力时,有人怎么能说“没有好话”。
    【解决方案7】:

    1) 我使用 print_r()。在 TextMate 中,我有一个用于 'pre' 的 sn-p,它扩展为:

    echo "<pre>";
    print_r();
    echo "</pre>";
    

    2) 我使用 Xdebug,但无法让 GUI 在我的 Mac 上正常工作。它至少打印出堆栈跟踪的可读版本。

    【讨论】:

    • 我确定你的意思是 echo "";最后。
    • 您也可以将 'true' 传递给函数,使其返回字符串。这意味着你可以这样做:echo '&lt;pre&gt;', print_r($var, true), '&lt;/pre&gt;';
    【解决方案8】:

    我使用了Zend Studio (5.5)Zend Platform。这提供了正确的调试、断点/跨代码等,尽管需要付出代价。

    【讨论】:

      【解决方案9】:

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

      我会说,直到我在 Uni 做了一些微处理器编程并且甚至无法使用它时,我才完全理解这一点。

      【讨论】:

      • 很高兴您提到了 print 和 print_r,我使用基本的 print 来查看代码是否执行到某个点,这有助于隔离问题。
      • 我同时使用 print 和 var_dump()。我使用 print 来显示调试消息和信息,并使用 var_dump 来指示变量在事情进展时的状态。
      【解决方案10】:

      Xdebug,作者 Derick Rethans,非常好。我前段时间用过,发现安装起来不是那么容易。一旦你完成了,你将无法理解没有它你是如何管理的:-)

      Zend Developer Zone 上有一篇好文章(在 Linux 上安装似乎并不容易),甚至还有一篇我从未使用过的 Firefox plugin

      【讨论】:

      • 令人沮丧的不仅仅是安装。将 Xdebug 配置为与 Eclipse 一起工作可能是一场噩梦。我能够在 CentOS 5 上安装 Xdebug,但 EclipsePDT+Xdebug 不想合作:(
      【解决方案11】:

      我使用带有 XDebug 的 Netbeans。 在其网站上查看有关如何配置它的文档。 http://php.netbeans.org/

      【讨论】:

        【解决方案12】:

        我使用带有 XDebug 和 Easy XDebug FireFox Add-on 的 Netbeans

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

        【讨论】:

          【解决方案13】:

          如果您不想弄乱输出,输出缓冲非常有用。我在单行中执行此操作,我可以随意评论/取消评论

           ob_start();var_dump(); user_error(ob_get_contents()); ob_get_clean();
          
          【解决方案14】:

          PhpEdit 有一个内置调试器,但我通常最终使用 echo();和 print_r();老式的方法!

          【讨论】:

            【解决方案15】:

            对于那些使用 print_r/echo 太费时间来弄清楚的真正棘手的问题,我使用了我的 IDE 的 (PhpEd) 调试功能。与我使用的其他 IDE 不同,PhpEd 几乎不需要任何设置。我不使用它来解决我遇到的任何问题的唯一原因是它的速度痛苦。我不确定缓慢是否特定于 PhpEd 或任何 php 调试器。 PhpEd 不是免费的,但我相信它无论如何都使用开源调试器之一(如前面提到的 XDebug)。再次,PhpEd 的好处是它不需要我过去发现非常乏味的设置。

            【讨论】:

            • PHPEd 调试器实际上是由编写 PHPEd 的同一个人编写的,我很确定它不是开源的。至少 PHPEd 不附带源代码,而是编译了 .so 和 .dll。
            【解决方案16】:

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

            【讨论】:

              【解决方案17】:

              嗯,在某种程度上,这取决于事情的发展方向。这是我尝试隔离的第一件事,然后我会根据需要使用 echo/print_r()。

              注意:你们知道可以将 true 作为第二个参数传递给 print_r(),它会返回输出而不是打印它?例如:

              echo "<pre>".print_r($var, true)."</pre>";
              

              【讨论】:

              • 我只是将它包装在一个名为 debug 的函数中。那么我可以做 debug($var);
              【解决方案18】:

              当无法使用 Rails 时,我经常使用 CakePHP。为了调试错误,我通常会在 tmp 文件夹中找到 error.log,然后在终端中使用命令将其拖尾...

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

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

              $this->log('xxxx');
              

              这通常可以让您很好地了解发生了什么/出了什么问题。

              【讨论】:

                【解决方案19】:

                print_r(debug_backtrace());

                或类似的东西:-)

                【解决方案20】:

                Komodo IDE 可以很好地与 xdebug 配合使用,甚至可以进行更多调试。它需要最少的配置。您只需要一个 php 版本,Komodo 可以在本地使用它来单步执行断点上的代码。如果您将脚本导入 komodo 项目,那么您可以通过单击鼠标设置断点,就像在 eclipse 中设置它以调试 java 程序一样。 与本地调试设置相比,远程调试显然更难让它正常工作(您可能必须在工作区中使用 php 脚本映射远程 URL),如果您在 MAC 或 Linux 桌面上,本地调试设置非常容易配置.

                【讨论】:

                  【解决方案21】:

                  Nusphere 也是一个很好的 php 调试器 nusphere

                  【讨论】:

                    【解决方案22】:

                    有许多 PHP 调试技术可以在编码时为您节省无数时间。一种有效但基本的调试技术是简单地打开错误报告。另一种更高级的技术涉及使用打印语句,它可以通过在屏幕上显示实际发生的内容来帮助查明更难以捉摸的错误。 PHPeclipse是一个Eclipse插件,可以高亮常见语法错误,可以配合调试器设置断点。

                    display_errors = Off
                    error_reporting = E_ALL 
                    display_errors = On
                    

                    也用过

                    error_log();
                    console_log();
                    

                    【讨论】:

                      【解决方案23】:

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

                      【讨论】:

                      • 和 tail -f ... 效果很好
                      【解决方案24】:

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

                      【讨论】:

                        【解决方案25】:

                        只需var_dump输入一些关键变量即可轻松找到大部分错误,但这显然取决于您开发的应用程序类型。

                        对于更复杂的算法,步进/断点/监视功能非常有用(如果没有必要)

                        【讨论】:

                          【解决方案26】:

                          PHP DBG

                          作为 SAPI 模块实现的交互式分步 PHP 调试器可让您完全控制环境,而不会影响代码的功能或性能。它旨在成为 PHP 5.4+ 的轻量级、功能强大、易于使用的调试平台,并且随 PHP 5.6 一起提供。

                          功能包括:

                          • 逐步调试
                          • 灵活的断点(类方法、函数、文件:行、地址、操作码)
                          • 使用内置 eval() 轻松访问 PHP
                          • 轻松访问当前正在执行的代码
                          • 用户区 API
                          • 与 SAPI 无关 - 轻松集成
                          • PHP 配置文件支持
                          • JIT Super Globals - 设置你自己的!!
                          • 可选的 readline 支持 - 舒适的终端操作
                          • 远程调试支持 - 捆绑的 Java GUI
                          • 操作简单

                          查看截图:

                          首页:http://phpdbg.com/

                          PHP Error - 更好的 PHP 错误报告

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

                          您唯一需要做的就是包含一个如下文件(在代码的开头):

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

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

                          功能包括:

                          • 简单易用,只有一个文件
                          • 正常和 ajaxy 请求在浏览器中显示的错误
                          • AJAX 请求已暂停,您可以自动重新运行它们
                          • 使错误尽可能严格(提高代码质量,并倾向于提高性能)
                          • 在整个堆栈跟踪中编写 sn-ps 代码
                          • 提供更多信息(例如完整的函数签名)
                          • 修复了一些完全错误的错误消息
                          • 语法高亮
                          • 看起来很漂亮!
                          • 定制
                          • 手动开启和关闭
                          • 运行特定部分而不报告错误
                          • 忽略文件,让您避免在堆栈跟踪中突出显示代码
                          • 应用程序文件;发生错误时优先处理这些内容!

                          首页:http://phperror.net/

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

                          我的叉子(有额外的修复):https://github.com/kenorb-contrib/PHP-Error

                          DTrace

                          如果您的系统支持DTrace dynamic tracing(默认安装在 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));
                          }
                          

                          主页:dtruss-lamp 在 GitHub

                          这里是简单的用法:

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

                          要对此进行测试,您可以使用index.php 访问任何文档根目录并通过以下方式运行 PHP 内置服务器:

                          php -S localhost:8080
                          

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

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

                          请参阅:Using PHP and 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
                          

                          请参阅:Using SystemTap with PHP DTrace Static Probes php.net

                          【讨论】:

                            【解决方案27】:

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

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

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

                            【解决方案28】:

                            根据问题,我喜欢将 error_reporting(E_ALL) 与 echo 测试结合使用(以找到最初发生错误的有问题的行/文件;您知道它并不总是 php 告诉您的行/文件对吗?), IDE 大括号匹配(解决“解析错误:语法错误,意外 $end”问题)和 print_r();出口;转储(真正的程序员查看源代码;p)。

                            你也不能用“memory_get_usage();”打败 phpdebug(检查 sourceforge)和“memory_get_peak_usage();”找出问题所在。

                            【讨论】:

                              【解决方案29】:

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

                              print_r 易于编写,保证在任何设置下都能正常工作。

                              【讨论】:

                                【解决方案30】:

                                通常我发现创建一个自定义日志函数能够保存在文件中,存储调试信息,并最终在公共页脚上重新打印。

                                你也可以重写普通的异常类,这样这种调试是半自动化的。

                                【讨论】:

                                  猜你喜欢
                                  • 2019-05-16
                                  • 2010-10-31
                                  • 2010-10-24
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2015-09-07
                                  相关资源
                                  最近更新 更多