有些情况下,需要知道某段php程序业务是否正常执行完,可以用 register_shutdown_function函数来辅助实现。
register_shutdown_function — 注册一个会在php中止时执行的函数,函数说明 定义:该函数是来注册一个会在PHP中止时执行的函数 参数说明:
void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )
1、它会在脚本执行完成或者 exit() 后被调用。
2、可以多次调用 register_shutdown_function() ,这些被注册的回调会按照他们注册时的顺序被依次调用。
3、如果你在注册的方法内部调用 exit(), 那么所有处理会被中止,并且其他注册的中止回调也不会再被调用。
PHP中止的情况 PHP中止的情况有三种:执行完成 、exit/die导致的中止、发生致命错误中止
a)、 第一种情况,执行完成。
function test() { echo '这个是中止方法test的输出'; } register_shutdown_function('test'); echo "before <br/>"; 运行: before 这个是中止方法test的输出 注意:输出的顺序,等执行完成了之后才会去执行 register_shutdown_function的中止方法test
b. 第二种情况,exit/die导致的中止
function test() { echo '这个是中止方法test的输出'; } register_shutdown_function('test'); echo "before <br/>"; exit(); echo "after <br/>"; 运行: before 这个是中止方法test的输出 后面的after并没有输出,即exit或者是die方法导致提前中止。
c. 第三种情况,发送致命错误中止
function test() { echo '这个是中止方法test的输出'; } register_shutdown_function('test'); echo "before <br/>"; $a = new a(); echo "after <br/>"; 运行:这个是中止方法test的输出 后面的after也是没有输出,。
参数的使用:
第一个参数支持以数组的形式来调用类中的方法,第二个以及后面的参数都是可以当做额外的参数传给中止方法。
class Shutdown { public function stop() { echo "这个是stop方法的输出"; } } // 当PHP终止的时候(执行完成或者是遇到致命错误中止的时候)会调用new Shutdown的stop方法 register_shutdown_function([new Shutdown(), 'stop']); // 将因为致命错误而中止 $a = new a(); // 这一句并没有执行,也没有输出 echo '必须终止';
也可以在类中执行:
class TestDemo { public function __construct() { register_shutdown_function([new TestDemo(), "f"], "hello"); } public function f($str) { echo "class TestDemo->f():" . $str; } } $demo = new TestDemo(); echo "before <br>"; /** 运行: before class TestDemo->f():hello */
同时调用多个 可以多次调用 register_shutdown_function,这些被注册的回调会按照他们注册时的顺序被依次调用。 不过注意的是,如果在第一个注册的中止方法里面调用exit方法或者是die方法的话,那么其他注册的中止回调也不会被调用。
function f($str) { echo $str . "<br>"; // 如果下面调用exit方法或者是die方法的话,其他注册的中止回调不会被调用 // exit(); } // 注册第一个中止回调f方法 register_shutdown_function("f", "hello"); class TestDemo { public function __construct() { register_shutdown_function([$this, "f"], "hello"); } public function f($str) { echo "class TestDemo->f():" . $str; } } $demo = new TestDemo(); echo "before <br>"; /*** 运行: before hello class TestDemo->f():hello 注意:如果f方法里面调用了exit或者是die的话,那么最后的class TestDemo->f():hello不会输出 */
该函数的作用:
1)、析构函数:在PHP4的时候,由于类不支持析构函数,所以这个函数经常用来模拟实现析构函数
2)、致命错误的处理:使用该函数可以用来捕获致命错误并且在发生致命错误后恢复流程处理,代码如下:
class Shutdown { public function stop() { echo 'Begin.' . PHP_EOL; // 如果有发生错误(所有的错误,包括致命和非致命)的话,获取最后发生的错误 if (error_get_last()) { print_r(error_get_last()); } // ToDo:发生致命错误后恢复流程处理 // 中止后面的所有处理 die('Stop.'); } } // 当PHP终止的时候(执行完成或者是遇到致命错误中止的时候)会调用new Shutdown的stop方法 register_shutdown_function([new Shutdown(), 'stop']); // 将因为致命错误而中止 $a = new a(); // 这一句并没有执行,也没有输出 echo '必须终止';
注意:PHP7中新增了Throwable异常类,这个类可以捕获致命错误,即可以使用 try...catch(Throwable $e)来捕获致命错误,代码如下:
try { // 将因为致命错误而中止 $a = new a(); // 这一句并没有执行,也没有输出 echo 'end'; } catch (Throwable $e) { print_r($e); echo $e->getMessage(); }
(小插曲 可以网上搜索phpwamp:http://www.phpwamp.com/ ,是一款纯绿色的PHP集成环境,集成多版本,拥有多种实用功能,可以用作服务器环境。 ),使用php 7来进行测试,该结果如图所示:
这样的话,PHP7中使用Throwable来捕获的话比使用 register_shutdown_function这个函数来得更方便,也更推荐Throwable。 注意:Error类也是可以捕获到致命错误,不过Error只能捕获致命错误,不能捕获异常Exception,而Throwable是可以捕获到错误和异常的,所以更推荐。
巧用 register_shutdown_function判断php程序是否执行完 还有一种应用场景就是:要做一个消费队列,因为某条有问题的数据导致致命错误,如果这条数据不处理掉,那么整个队列都会导致瘫痪的状态,这样可以用以下方法来解决。即:如果捕获到有问题的数据导致错误,则在回调函数中将这条数据处理掉就可以了。
register_shutdown_function('myFun'); //放到最上面,不然如果下面有致命错误,就不会调用myFun了。 $execDone = false; //程序是否成功执行完(默认为false) /** ********************* 业务逻辑区************************* */ $tas = 3; if($tas == 3) { new daixiaorui(); } /** ********************* 业务逻辑结束************************* */ $execDone = true; //由于程序由上至下执行,因此当执行到此后,则证明逻辑没有出现致命的错误。 function myFun() { global $execDone; if($execDone === false) { file_put_contents("d:/myMsg.txt", date("Y-m-d H:i:s")."---error: 程序执行出错。\r\n", FILE_APPEND); /******** 以下可以做一些处理 ********/ } }
register_shutdown_function 常搭配 error_get_last()使用,可以用来记录我们的错误日志:
function phpBinShutdownFun() { $error = error_get_last(); if ($error && (in_array($error['type'], array(1,16,32,64,128))) ) // 严重错误才允许报警 { // 写入报警文件中 $errorMsg = "errTm:".date("Y-m-d H:i:s") . "#errType:{$error['type']}#msg:{$error['message']}#file:[{$_SERVER['PHP_SELF']}]{$error['file']}#line:{$error['line']}\n"; file_put_contents("/da0/logs/phpBinError.log".ENV, $errorMsg, FILE_APPEND); } } register_shutdown_function( "phpBinShutdownFun" );
总结 :
register_shutdown_function这个函数主要是用在处理致命错误的后续处理上(PHP7更推荐使用Throwable来处理致命错误),不过缺点也很明显,只能处理致命错误Fatal error,其他的错误包括最高错误Parse error也是没办法处理的。
参考:
微信公众号:PHP技术大全
http://blog.csdn.net/tdcqfyl/article/details/52291237
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn