嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

菜单开关

周梦康 发表于 2018-03-21 399 次浏览 标签 : PHP框架笔记phpsymfony

实验

承接上一篇:https://mengkang.net/978.html

Symfony 命令行是如何把错误转成异常的呢?

 PHP 错误日志收集之 ErrorException

原来是使用了ErrorException

http://php.net/manual/en/class.errorexception.php

有了这个类就太好了,命令行可能感触不是特别明显,对于 web 来说简直就是福音了。

下面做一个小实验,当什么都没有设置的时候,以下代码和其错误信息如下:

function testError(){
  return explode("xxx");
}

testError();
[21-Mar-2018 15:42:25 PRC] PHP Warning:  explode() expects at least 2 parameters, 1 given in /xxx/test.php on line 4

看不到具体的参数,也看不到调用栈。这里没有演示,比如很多函数的相互嵌套调用。仅仅这一行,很难知道这个请求的具体流程。(这一行演示不明显,可以自己加几个文件的包含)。

将代码改成

function testError(){
  return explode("xxx");
}

try{
  testError();
}catch(Exception $e){
  var_export($e->getTrace());
}

echo 1;

页面能正常输出1,但是无法打印出异常的调用栈,php 错误日志里面和没有使用try-catch 一样,没有调用栈。

改进

然后我们如果使用set_error_handler + ErrorException之后,就非常清晰了,很便于错误的追踪。

function my_error_handler($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
}

set_error_handler("my_error_handler");

function testError(){
  return explode("xxx");
}

try{
  testError();
}catch(Exception $e){
  var_export($e->getTrace());
}

最后打印出来的信息就是

array (
  0 => 
  array (
    'function' => 'exception_error_handler',
    'args' => 
    array (
      0 => 2,
      1 => 'explode() expects at least 2 parameters, 1 given',
      2 => '/Users/zhoumengkang/Downloads/xxx.php',
      3 => 19,
      4 => 
      array (
      ),
    ),
  ),
  1 => 
  array (
    'file' => '/Users/zhoumengkang/Downloads/xxx.php',
    'line' => 19,
    'function' => 'explode',
    'args' => 
    array (
      0 => 'xxx',
    ),
  ),
  2 => 
  array (
    'file' => '/Users/zhoumengkang/Downloads/xxx.php',
    'line' => 12,
    'function' => 'testError',
    'args' => 
    array (
    ),
  ),
)

这样就能看见着整个调用栈和每个函数的传递的参数。不仅仅是这些信息,因为通过set_error_handler接管了错误处理,所以在出现该错误的其他信息都可以记录了,方便错误的重现和追踪。

Uncaught TypeError

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

function testError1($context){
    return explode($context);
}

function testError2(array $context){
    return false;
}


try{
//    testError1(111);
    testError2(111);
}catch(Exception $e){
    var_export($e->getTrace());
}

Fatal error: Uncaught TypeError: Argument 1 passed to testError2() must be of the type array, integer given, called in

改进,但有不足

set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});

register_shutdown_function(function(){
    $e = error_get_last();
    if ($e){
        var_export($e);
    }
});

function testError1($a){
    return $a*10;
}

function testError2(array $context){
    return false;
}

try{
    $b = testError1(6666);
    testError2($b);
}catch(Exception $e){
    var_export($e->getTrace());
}
array (
  'type' => 1,
  'message' => 'Uncaught TypeError: Argument 1 passed to testError2() must be of the type array, integer given, called in xxx.php on line 32 and defined in xxx.php:26
Stack trace:
#0 xxx.php(32): testError2(66660)
#1 {main}
  thrown',
  'file' => 'xxx.php',
  'line' => 26,
)

依然看不到完整的调用栈。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表