您如何调试PHP脚本?
我知道诸如使用错误报告之类的基本调试。PHPEclipse中的断点调试也非常有用。
在phpStorm或任何其他IDE中进行调试的最佳方式(快速简便)是什么?
您如何调试PHP脚本?
我知道诸如使用错误报告之类的基本调试。PHPEclipse中的断点调试也非常有用。
在phpStorm或任何其他IDE中进行调试的最佳方式(快速简便)是什么?
Answers:
尝试使用Eclipse PDT来设置一个具有上述调试功能的Eclipse环境。与旧方法var_dump相比,调试代码的能力是一种更好的方法,它可以在各个点进行打印并在各个位置进行打印,以查看流向哪里出错。但是,当所有其他方法都失败了,而我所拥有的只是SSH和vim时,我仍然var_dump()
/ die()
找出代码在哪里。
kill($data) { echo "<pre>"; var_dump($data); echo "</pre>"; exit; }
您可以在与javascript相同的环境中使用Firephp加载项对Firebug进行调试。
我还使用前面提到的Xdebug来分析php。
这是我的小调试环境:
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;
}
}
}
assert_callcack
嘿
XDebug对于开发至关重要。我先安装它,再安装其他任何扩展程序。它为您提供了有关任何错误的堆栈跟踪,并且您可以轻松启用分析。
为了快速查看数据结构,请使用var_dump()
。不要使用print_r()
它,因为您必须将它包围起来,<pre>
并且一次只能打印一个变量。
<?php var_dump(__FILE__, __LINE__, $_REQUEST); ?>
对于真正的调试环境,我发现的最好的是Komodo IDE,但价格为$$。
PhpEd真的很好。您可以进入/超过/退出功能。您可以运行临时代码,检查变量,更改变量。太神奇了
1)我使用print_r()。在TextMate中,我有一个'pre'的代码片段,它扩展为:
echo "<pre>";
print_r();
echo "</pre>";
2)我使用Xdebug,但无法在Mac上正常运行GUI。它至少打印出堆栈跟踪的可读版本。
echo '<pre>', print_r($var, true), '</pre>';
我使用了Zend Studio(5.5)和Zend Platform。尽管付出了一定的代价,但这却可以提供适当的调试,断点/单步执行代码等功能。
Xdebug的Derick Rethans的非常好。我前一段时间使用它,发现它并不是那么容易安装。一旦完成,您将不了解没有它的管理方式:-)
在Zend Developer Zone上有一篇不错的文章(在Linux上安装似乎并不容易),甚至还有一个我从未使用过的Firefox插件。
我将Netbeans与XDebug一起使用。在其网站上查看有关如何配置它的文档。 http://php.netbeans.org/
我将Netbeans与XDebug和Easy XDebug FireFox附件一起使用
在调试MVC项目时,该附件是必不可少的,因为XDebug在Netbeans中运行的正常方式是通过url注册dbug会话。在FireFox中安装了附加组件之后,您将设置Netbeans项目属性->运行配置->高级并选择“不打开Web浏览器”。现在,您可以像往常一样设置断点并使用Ctrl-F5开始调试会话。打开FireFox,然后右键单击右下角的“加载项”图标以开始监视断点。当代码到达断点时,它将停止,您可以检查变量状态和调用堆栈。
如果您不想弄乱输出,则输出缓冲非常有用。我采用单行代码执行此操作,我可以随意评论/取消评论
ob_start();var_dump(); user_error(ob_get_contents()); ob_get_clean();
对于确实很棘手的问题,使用print_r / echo来弄清时间太费时了,我使用我的IDE的(PhpEd)调试功能。与我使用过的其他IDE不同,PhpEd几乎不需要进行任何设置。我不使用它,因为我遇到任何问题,唯一的原因是,它是痛苦的缓慢。我不确定速度是否特定于PhpEd或任何php调试器。PhpEd不是免费的,但我相信它还是会使用一种开源调试器(如前面提到的XDebug)。同样,PhpEd的好处在于它不需要任何设置,而我在过去发现这非常繁琐。
好吧,这在某种程度上取决于事情向南发展。这是我尝试隔离的第一件事,然后根据需要使用echo / print_r()。
注意:你们知道您可以将true作为第二个参数传递给print_r(),它将返回输出而不是打印输出?例如:
echo "<pre>".print_r($var, true)."</pre>";
print_r(debug_backtrace());
或类似的东西 :-)
作为SAPI模块实现的交互式逐步调试PHP调试器,可以使您完全控制环境,而不会影响代码的功能或性能。它旨在成为适用于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动态跟踪(默认情况下安装在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();"
。为了测试这一点,您可以使用以下命令转到任何docroot index.php
并运行PHP内置服务器:
php -S localhost:8080
之后,您可以访问该站点 http:// localhost:8080 /(或选择任何适合您的端口)。从那里访问一些页面以查看跟踪输出。
注意:默认情况下,Dtrace在OS X上可用,在Linux上,您可能需要dtrace4linux或检查其他替代方法。
请参阅:在php.net上使用PHP和DTrace
或者,通过安装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
请参阅:使用了SystemTap与DTrace的PHP静电探测器在php.net
为print_r()+1。用它来转储对象或变量的内容。为了使其更具可读性,请使用pre标记,这样就无需查看源代码。
echo '<pre>';
print_r($arrayOrObject);
也是var_dump($ thing)-这对于查看subthings的类型非常有用
通常,我发现创建一个自定义日志功能,该功能可以保存在文件中,存储调试信息,并最终在通用页脚上重新打印。
您还可以覆盖常见的Exception类,以便这种调试是半自动的。