前言
最近在看《PHP核心技术与最佳实践》,里面有使用到一个函数,register_shutdown_function,由于之前没有用过该函数,就去查了一下资料,就觉得是个很实用的函数,所以这里写一下这个函数的用法。下面话不多说了,来一起看看详细的介绍吧。
1. 函数说明
参数说明:
注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用。
callback:待注册的中止回调
parameter:可以通过传入额外的参数来将参数传给中止函数
2. PHP中止的情况
PHP中止的情况有三种:
- 执行完成
- exit/die导致的中止
- 发生致命错误中止
a. 第一种情况,执行完成
register_shutdown_function('test');
echo 'before' . PHP_EOL;
运行:
注意:输出的顺序,等执行完成了之后才会去执行register_shutdown_function的中止方法test
b. 第二种情况,exit/die导致的中止
运行:
后面的after并没有输出,即exit或者是die方法导致提前中止。
c. 第三种情况,发送致命错误中止
register_shutdown_function('test');
echo 'before' . PHP_EOL;
// 这里会发生致命错误
$a = new a();
echo 'after' . PHP_EOL;
运行:
Fatal error: Uncaught Error: Class 'a' not found in D:\laragon\www\PHP_book\test.PHP on line 12
Error: Class 'a' not found in D:\laragon\www\PHP_book\test.PHP on line 12
Call Stack:
0.0020 360760 1. {main}() D:\laragon\www\PHP_book\test.PHP:0
3. 参数
第一个参数支持以数组的形式来调用类中的方法,第二个以及后面的参数都是可以当做额外的参数传给中止方法。
class Shutdown
{
public function stop()
{
echo "这个是stop方法的输出";
}
}
// 当PHP终止的时候(执行完成或者是遇到致命错误中止的时候)会调用new Shutdown的stop方法
register_shutdown_function([new Shutdown(),'stop']);
// 将因为致命错误而中止
$a = new a();
// 这一句并没有执行,也没有输出
echo '必须终止';
也可以在类中执行:
public function __construct()
{
register_shutdown_function([$this,"f"],"hello");
}
public function f($str)
{
echo "class TestDemo->f():" . $str;
}
}
$demo = new TestDemo();
echo 'before' . PHP_EOL;
/*
运行:
before
class TestDemo->f():hello
/
4. 同时调用多个
可以多次调用 register_shutdown_function,这些被注册的回调会按照他们注册时的顺序被依次调用。
不过注意的是,如果在第一个注册的中止方法里面调用exit方法或者是die方法的话,那么其他注册的中止回调也不会被调用。 代码:
- @param $str
*/
function f($str) {
echo $str . PHP_EOL;
// 如果下面调用exit方法或者是die方法的话,其他注册的中止回调不会被调用
// exit();
}
// 注册第一个中止回调f方法
register_shutdown_function("f","hello");
class TestDemo {
public function __construct()
{
register_shutdown_function([$this,"hello");
}
public function f($str)
{
echo "class TestDemo->f():" . $str;
}
}
$demo = new TestDemo();
echo 'before' . PHP_EOL;
/**
运行:
before
hello
class TestDemo->f():hello
注意:如果f方法里面调用了exit或者是die的话,那么最后的class TestDemo->f():hello不会输出
*/
5. 用处
该函数的作用:
析构函数:在PHP4的时候,由于类不支持析构函数,所以这个函数经常用来模拟实现析构函数
致命错误的处理:使用该函数可以用来捕获致命错误并且在发生致命错误后恢复流程处理
代码如下:
class Shutdown
{
public function stop()
{
echo 'Begin.' . PHP_EOL;
// 如果有发生错误(所有的错误,包括致命和非致命)的话,获取最后发生的错误
if (error_get_last()) {
print_r(error_get_last());
}
// 中止后面的所有处理
die('Stop.');
}
}
// 当PHP终止的时候(执行完成或者是遇到致命错误中止的时候)会调用new Shutdown的stop方法
register_shutdown_function([new Shutdown(),'stop']);
// 将因为致命错误而中止
$a = new a();
// 这一句并没有执行,也没有输出
echo '必须终止';
运行:
Call Stack:
0.0060 362712 1. {main}() D:\laragon\www\php_book\1_23_register_shutdown.php:0
Begin.
Array
(
[type] => 1
[message] => Uncaught Error: Class 'a' not found in D:\laragon\www\PHP_book\1_23_register_shutdown.PHP:31
Stack trace:
0 {main}
thrown
[file] => D:\laragon\www\PHP_book\1_23_register_shutdown.PHP
[line] => 31
)
Stop.
注意:PHP7中新增了Throwable异常类,这个类可以捕获致命错误,即可以使用try...catch(Throwable $e)来捕获致命错误,代码如下:
// 将因为致命错误而中止
$a = new a();
// 这一句并没有执行,也没有输出
echo 'end';
} catch (Throwable $e) {
print_r($e);
echo $e->getMessage();
}
运行:
[prevIoUs:Error:private] =>
[xdebug_message] =>
Error: Class 'a' not found in C:\laragon\www\PHP_book\throwable.PHP on line 5
Call Stack:
0.0000 349856 1. {main}() C:\laragon\www\PHP_book\throwable.PHP:0
)
Class 'a' not found
这样的话,PHP7中使用Throwable来捕获的话比使用register_shutdown_function这个函数来得更方便,也更推荐Throwable。
注意:Error类也是可以捕获到致命错误,不过Error只能捕获致命错误,不能捕获异常Exception,而Throwable是可以捕获到错误和异常的,所以更推荐。
6.巧用register_shutdown_function判断PHP程序是否执行完
还有一种应用场景就是:要做一个消费队列,因为某条有问题的数据导致致命错误,如果这条数据不处理掉,那么整个队列都会导致瘫痪的状态,这样可以用以下方法来解决。即:如果捕获到有问题的数据导致错误,则在回调函数中将这条数据处理掉就可以了。
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("E:/myMsg.txt",date("Y-m-d H:i:s")."---error: 程序执行出错。\r\n",FILE_APPEND);
/**** 以下可以做一些处理 ****/
}
}
总结
register_shutdown_function这个函数主要是用在处理致命错误的后续处理上(PHP7更推荐使用Throwable来处理致命错误),不过缺点也很明显,只能处理致命错误Fatal error,其他的错误包括最高错误Parse error也是没办法处理的。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程之家的支持。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。