PHP 自动捕获 Fatal Error

本文详细介绍PHP中如何使用set_error_handler和set_exception_handler捕获警告、错误和异常,包括如何处理Notice级别错误及致命错误(Fatal Error),并提供代码示例说明register_shutdown_function和error_get_last的使用技巧。

PHP 有捕获 Error 和 Exception 的函数

设置一个用户的函数来处理脚本中出现的错误。

set_error_handler($callback)

//设置一个用户的函数来处理脚本中出现的异常。

set_exception_handler($callback)

测试异常捕获

<?php
//设置异常捕获函数
set_exception_handler("my_exception");
function my_exception($exception){
    echo 'Exception Catched:'.$exception->getMessage();
}
//抛出异常
throw new Exception("I am Exception");

ok


测试错误捕获

<?php
set_error_handler("error_handler");
function error_handler($errno,$errstr,$errfile,$errline){
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//获取到错误可以自己处理,比如记 Log、报警等等
    echo $str;
}
echo $test;//$test 未定义,会报一个 notice 级别的错误

不错,Notice 级别的错误也捕获到了! 接下来再测一下 Fatal Error.

<?php
set_error_handler("error_handler");
function error_handler($errno,$errstr,$errfile,$errline){
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//获取到错误可以自己处理,比如记 Log、报警等等
    echo $str;
}
//调用一个不存在的函数,会出现 Fatal Error
test();

Fatal Error 竟然没捕获到

以下级别的错误不能由用户定义的函数来处理:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。

也就是:set_error_handler($callback)只能捕获系统产生的一些 Warning、Notice 级别的 Error。

要实现这个需求,需要用到两个函数:register_shutdown_function()和error_get_last()。

register_shutdown_function()

register_shutdown_function($callback)

register_shutdown_function(),就把你要注册进去的 function 放进 [假装是队列吧] ,等到脚本正常退出或显式调用 exit()时,再把注册进去的 function 拉出来执行.

register_shutdown_function()调用的 3 种情况:

脚本正常退出时;
在脚本运行(run-time not parse-time)出错退出时;
用户调用 exit 方法退出时。

error_get_last()

error_get_last();//函数获取最后发生的错误。
该函数以数组的形式返回最后发生的错误。

返回的数组包含 4 个键和值: [type] - 错误类型 [message] - 错误消息 [file] - 发生错误所在的文件 [line] - 发生错误所在的行

强烈注意

在 parse-time 出错的时候,是不会调用 register_shutdown_function()函数的。只有在 run-time 出错的时候,才会调用 register_shutdown_function()。

为了更好的理解,下面我们举例说明:

1.error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
function test(){}
function test(){}

原因分析
在执行 error_handler.php 的时候,由于重复定义了两个函数 test(),在 php 的 parse-time 就出错了(不是 run-time ),所以不能回调 register_shutdown_function()中注册的函数。

2.error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}
if(true){
   function test(){}
}
function test(){}

原因分析
我们看到,上面回调了 register_shutdown_function()中注册的函数。 因为我们加了一个 if()判断,if()里面的 test()方法,相当于一个闭包,与外面的 test()名称不冲突。 也就是,上面的代码在 parse-time 没有出错,而是在 run-time 的时候出错了,所以我们能够获取到 fatal error。

3.error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}

test.php

<?php
include './error_handler.php';
function test(){}
function test(){}

原因分析
当我们在运行 test.php 的时候,因为 redeclare 了两个 test()方法,所以 php 的语法解析器在 parse-time 的时候就出错了。 所以不能回调 register_shutdown_function()中的方法,不能 catch 住这个 fatal error。

4.error_handler.php

<?php
register_shutdown_function("error_handler");
function error_handler(){
    echo "Yeah,it's worked!";
}

test.php

<?php
function test(){}
function test(){}

include_all.php

<?php
require './error_handler.php';
require './test.php';

执行 include_all.php  

结果分析
上面我们捕获了 fatal_error。 因为在运行 include_all.php 的时候,include_all.php 本身语法并没有出错,也就是在 parse-time 的时候并没有出错,而是 include 的文件出错了,也就是在 run-time 的时候出错了,这个时候是能回调 register_shutdown_function()中的函数的。

强烈建议:如果我们要使用 register_shutdown_function 进行错误捕捉,使用最后一种方法,可以确保错误都能捕捉到。error_handler 脚本吧,确保每次都能获取到想要的 Fatal Error

<?php
register_shutdown_function( "fatal_handler" );
set_error_handler("error_handler");

define('E_FATAL',  E_ERROR | E_USER_ERROR |  E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR| E_PARSE );

//获取 fatal error
function fatal_handler() {
    $error = error_get_last();
    if($error && ($error["type"]===($error["type"] & E_FATAL))) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];
        error_handler($errno,$errstr,$errfile,$errline);
  }
}
//获取所有的 error
function error_handler($errno,$errstr,$errfile,$errline){
    $str=<<<EOF
         "errno":$errno
         "errstr":$errstr
         "errfile":$errfile
         "errline":$errline
EOF;
//获取到错误可以自己处理,比如记 Log、报警等等
    echo $str;
}

 

PHP 启动时出现 `Fatal error: Unable to start standard module Unknown line 0` 是一种较为罕见但严重的错误,通常与 PHP 的模块加载机制或扩展配置相关。该错误表明 PHP 在尝试加载某个标准模块时遇到问题,导致无法正常启动。 ### 错误原因分析 1. **模块加载失败** PHP 内核在加载标准模块时,如果某个模块未能正确初始化,可能导致此错误。例如,某些内置模块(如 `standard`、`session` 或 `date`)的注册失败会触发该异常[^1]。 2. **PHP 编译或安装问题** 如果 PHP 是从源码编译安装的,可能由于编译过程中的配置错误或模块未正确链接,导致某些核心模块无法被加载。 3. **扩展冲突或损坏** 某些第三方扩展可能与标准模块发生冲突,尤其是在 `php.ini` 中启用了不兼容的扩展模块。 4. **共享库路径问题** 在某些系统上,如果 `extension_dir` 配置指向错误的路径,PHP 无法找到 `.so` 或 `.dll` 扩展文件,也可能引发此类错误。 ### 解决方案 #### 1. 检查 PHP 模块加载状态 运行以下命令查看模块加载情况: ```bash php -m ``` 如果发现某些核心模块缺失(如 `Core`、`standard` 等),则说明模块加载失败。 #### 2. 检查 `php.ini` 配置 确保 `php.ini` 文件中没有错误的扩展配置。可以尝试使用默认的 `php.ini` 文件进行替换,以排除配置问题。 #### 3. 重新编译或安装 PHP 如果怀疑是安装问题,可以尝试重新编译或安装 PHP: ```bash ./configure --enable-option-checking=fatal make clean make sudo make install ``` 确保编译选项中包含必要的模块,例如: ```bash --enable-cli --with-config-file-path=/etc/php --enable-mbstring --enable-zip ``` #### 4. 检查扩展兼容性 临时禁用所有第三方扩展,仅保留核心模块,查看问题是否仍然存在。可以在 `php.ini` 中注释掉所有 `extension=` 行进行测试。 #### 5. 使用调试工具 可以使用 `gdb` 调试 PHP CLI 启动过程,捕获更详细的错误信息: ```bash gdb php run ``` #### 6. 检查系统日志 查看系统日志(如 `/var/log/syslog` 或 `dmesg` 输出),可能包含与模块加载相关的错误信息。 --- ### 示例:检查 PHP 模块加载 ```bash php -r "phpinfo();" ``` 观察输出中是否有关于模块加载失败的提示。 --- ### 示例:替换 `php.ini` 文件 ```bash sudo cp /path/to/php.ini-development /usr/local/lib/php.ini ``` 然后重新运行 PHP CLI 命令查看是否解决。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值