如何调试 PHP 脚本?
我知道基本调试,例如使用错误报告。 PHPEclipse 中的断点调试也非常有用。
在phpStorm或任何其他IDE中调试的最佳(快速简便)方法是什么?
答案 0 :(得分:145)
尝试Eclipse PDT来设置具有您提到的调试功能的Eclipse环境。进入代码的能力是调试var_dump的旧方法并在各个点打印以查看流程出错的更好方法。当所有其他方法都失败但我所拥有的只有SSH和vim时,我仍然var_dump()
/ die()
找到代码向南的位置。
答案 1 :(得分:80)
你可以使用Firephp作为firebug的附加组件来在与javascript相同的环境中调试php。
我还使用前面提到的Xdebug来分析php。
答案 2 :(得分:38)
这是我的小调试环境:
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;
}
}
}
答案 3 :(得分:32)
Xdebug和用于Notepad ++的DBGp插件,用于重载bug,FirePHP用于轻量级的东西。快又脏?没有什么比dBug好。
答案 4 :(得分:26)
XDebug对发展至关重要。我在任何其他扩展之前安装它。它为您提供任何错误的堆栈跟踪,您可以轻松启用分析。
要快速查看数据结构,请使用var_dump()
。请勿使用print_r()
,因为您必须使用<pre>
将其包围,并且一次只打印一个var。
<?php var_dump(__FILE__, __LINE__, $_REQUEST); ?>
对于真正的调试环境,我发现的最好的是Komodo IDE,但它的成本为$$。
答案 5 :(得分:19)
PhpEd真的很棒。您可以进入/退出/退出功能。您可以运行特殊代码,检查变量,更改变量。太棒了。
答案 6 :(得分:17)
1)我使用print_r()。在TextMate中,我有一个“pre”的片段,它扩展为:
echo "<pre>";
print_r();
echo "</pre>";
2)我使用Xdebug,但无法让GUI在我的Mac上正常工作。它至少打印出堆栈跟踪的可读版本。
答案 7 :(得分:16)
老实说,print和print_r()的组合可以打印出变量。我知道很多人更喜欢使用其他更先进的方法,但我发现这是最容易使用的方法。
我会说,直到我在Uni做了一些微处理器编程并且甚至无法使用它,我才完全理解这一点。
答案 8 :(得分:16)
我已使用Zend Studio (5.5)和Zend Platform。这给了适当的调试,断点/踩到代码等,虽然付出了代价。
答案 9 :(得分:14)
Xdebug非常好。我前段时间使用它,发现安装起来并不容易。完成后,如果没有它,你将无法理解你的管理方式: - )
Zend Developer Zone上有一篇很好的文章(在Linux上安装似乎并不容易),甚至还有Firefox plugin,我从未使用过。
答案 10 :(得分:11)
我将Netbeans与XDebug和Easy XDebug FireFox Add-on
一起使用在调试MVC项目时,附加组件是必不可少的,因为XDebug在Netbeans中运行的正常方式是通过url注册dbug会话。使用FireFox中安装的附加组件,您可以设置Netbeans项目属性 - &gt;运行Configuratuion - &gt;高级并选择“不打开Web浏览器”您现在可以像往常一样使用Ctrl-F5设置断点并启动调试会话。打开FireFox并右键单击右下角的Add-on图标以开始监视断点。当代码到达断点时,它将停止,您可以检查变量状态和调用堆栈。
答案 11 :(得分:11)
我使用Netbeans和XDebug。 请在其网站上查看有关如何配置它的文档。 http://php.netbeans.org/
答案 12 :(得分:10)
如果您不想弄乱输出,输出缓冲非常有用。我这样做是单行的,我可以随意评论/取消评论
ob_start();var_dump(); user_error(ob_get_contents()); ob_get_clean();
答案 13 :(得分:9)
PhpEdit有一个内置的调试器,但我通常最终使用echo();和print_r();老式的方式!!
答案 14 :(得分:8)
对于使用print_r / echo来解决问题而非常耗时的问题,我使用了我的IDE(PhpEd)调试功能。与我使用的其他IDE不同,PhpEd几乎不需要设置。我遇到的任何问题我不使用它的唯一原因是它痛苦慢。我不确定缓慢是特定于PhpEd还是任何php调试器。 PhpEd不是免费的,但我相信它使用了一个开源调试器(如前面提到的XDebug)。再次,PhpEd带来的好处是它不需要我在过去发现的任何设置非常繁琐。
答案 15 :(得分:4)
手动调试对我来说通常更快 - var_dump()
和debug_print_backtrace()
是您制作逻辑所需的所有工具。
答案 16 :(得分:3)
当Rails无法使用时,我经常使用CakePHP。要调试错误,我通常会在tmp文件夹中找到error.log
,并使用命令在终端中将其拖尾...
tail -f app/tmp/logs/error.log
它让你从正在运行的蛋糕中运行对话框,这非常方便,如果你想在你可以使用的代码中输出一些内容。
$this->log('xxxx');
这通常可以让你很好地了解发生了什么/错误。
答案 17 :(得分:3)
注意:你们知道你可以传递true作为print_r()的第二个参数,它会返回输出而不是打印输出吗? E.g:
echo "<pre>".print_r($var, true)."</pre>";
答案 18 :(得分:2)
有许多PHP调试技术可以在编码时为您节省大量时间。一种有效但基本的调试技术是简单地打开错误报告。另一种稍微先进的技术涉及使用打印语句,它可以通过显示实际进入屏幕的内容来帮助查明更难以捉摸的错误。 PHPeclipse是一个Eclipse插件,可以突出显示常见的语法错误,可以与调试器一起使用来设置断点。
display_errors = Off
error_reporting = E_ALL
display_errors = On
并且还使用了
error_log();
console_log();
答案 19 :(得分:2)
Nusphere也是一个很好的php调试器 nusphere
答案 20 :(得分:2)
print_r(debug_backtrace());
或类似的东西: - )
答案 21 :(得分:2)
Komodo IDE与xdebug配合得很好,即使是对于remore调试也是如此。它需要最少量的配置。您所需要的只是一个PHP版本,Komodo可以在本地使用它来逐步执行断点代码。如果您将脚本导入到komodo项目中,那么您可以通过鼠标单击设置断点,只需在eclipse中设置它以调试java程序。 远程调试显然更难以使其正常工作(您可能必须使用工作区中的php脚本映射远程URL),而不是本地调试设置,如果您在MAC或Linux桌面上,这很容易配置
答案 22 :(得分:1)
只需var_dump
一些关键变量即可轻松找到大多数错误,但这显然取决于您开发的应用程序类型。
对于更复杂的算法,步/断点/监视功能非常有用(如果没有必要)
答案 23 :(得分:1)
Interactive Stepthrough PHP Debugger实现为SAPI模块,可以让您完全控制环境,而不会影响代码的功能或性能。它旨在成为一个轻量级,功能强大,易于使用的PHP 5.4+调试平台,并且它已经开箱即用,带有PHP 5.6。
功能包括:
参见截图:
这是非常容易使用的库(实际上是一个文件)来调试PHP脚本。
您唯一需要做的就是在下面添加一个文件(在代码的开头):
require('php_error.php');
\php_error\reportErrors();
然后所有错误都会为您提供回溯,代码上下文,函数参数,服务器变量等信息。例如:
功能包括:
GitHub:https://github.com/JosephLenton/PHP-Error
我的分叉(有额外的修复):https://github.com/kenorb-contrib/PHP-Error
如果您的系统支持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));
}
主页: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或检查其他alternatives。
请参阅:php.net上的Using PHP and DTrace
或者通过安装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
请参阅:php.net上的Using SystemTap with PHP DTrace Static Probes
答案 24 :(得分:1)
我使用内置调试器将end studio用于eclipse。与使用xdebug进行eclipse pdt调试相比,它仍然很慢。希望他们能解决这些问题,速度比最近发布的版本有所提升,但仍然需要2-3秒。 zend firefox工具栏确实让事情变得简单(调试下一页,当前页面等)。它还提供了一个分析器,可以对代码进行基准测试,并提供饼图,执行时间等。
答案 25 :(得分:1)
在生产环境中,我使用error_log()将相关数据记录到服务器的错误日志中。
答案 26 :(得分:0)
通常我发现创建一个自定义日志功能,可以保存文件,存储调试信息,并最终在公共页脚上重新打印。
您还可以覆盖常见的Exception类,以便这种类型的调试是半自动的。
答案 27 :(得分:0)
您可以在逐步执行代码时观察变量值的集成调试器非常酷。但是,它们需要在服务器上设置软件并在客户端上进行一定量的配置。两者都需要定期维护以保持良好的工作状态。
print_r易于编写,并保证可以在任何设置中使用。
答案 28 :(得分:0)
根据问题,我喜欢将error_reporting(E_ALL)与echo测试混合在一起(为了找到错误的行/文件,错误发生在初始;你知道它并不总是行/文件php告诉你对吗?), IDE大括号匹配(解决“解析错误:语法错误,意外的$ end”问题)和print_r();出口;转储(真正的程序员查看源; p)。
你也无法用“memory_get_usage();”击败phpdebug(检查sourceforge)和“memory_get_peak_usage();”找到问题所在。
答案 29 :(得分:0)
+1。用它来转储对象或变量的内容。为了使其更具可读性,请使用pre标签进行操作,这样您就不需要查看源代码。
echo '<pre>';
print_r($arrayOrObject);
var_dump($ thing) - 这对于查看子项的类型非常有用