PHP中register_shutdown_function函数的基础介绍与用法详解


Posted in PHP onNovember 28, 2017

前言

最近在看《PHP核心技术与最佳实践》,里面有使用到一个函数,register_shutdown_function,由于之前没有用过该函数,就去查了一下资料,就觉得是个很实用的函数,所以这里写一下这个函数的用法。下面话不多说了,来一起看看详细的介绍吧。

1. 函数说明

定义:该函数是来注册一个会在PHP中止时执行的函数

参数说明:

void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )

注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用。

callback:待注册的中止回调

parameter:可以通过传入额外的参数来将参数传给中止函数

2. PHP中止的情况

PHP中止的情况有三种:

  • 执行完成
  • exit/die导致的中止
  • 发生致命错误中止

a. 第一种情况,执行完成

<?php 
function test() 
{ 
 echo '这个是中止方法test的输出'; 
} 
 
register_shutdown_function('test'); 
 
echo 'before' . PHP_EOL;

运行:

before 
这个是中止方法test的输出

注意:输出的顺序,等执行完成了之后才会去执行register_shutdown_function的中止方法test

b. 第二种情况,exit/die导致的中止

<?php 
function test() 
{ 
 echo '这个是中止方法test的输出'; 
} 
 
register_shutdown_function('test'); 
 
echo 'before' . PHP_EOL; 
exit(); 
echo 'after' . PHP_EOL;

运行:

before 
这个是中止方法test的输出

后面的after并没有输出,即exit或者是die方法导致提前中止。

c. 第三种情况,发送致命错误中止

<?php 
function test() 
{ 
 echo '这个是中止方法test的输出'; 
} 
 
register_shutdown_function('test'); 
 
echo 'before' . PHP_EOL; 
 
// 这里会发生致命错误 
$a = new a(); 
 
echo 'after' . PHP_EOL;

运行:

before 
 
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 
 
这个是中止方法test的输出

后面的after也是没有输出,致命错误导致提前中止了。

3. 参数

第一个参数支持以数组的形式来调用类中的方法,第二个以及后面的参数都是可以当做额外的参数传给中止方法。

<?php 
 
class Shutdown 
{ 
 public function stop() 
 { 
  echo "这个是stop方法的输出"; 
 } 
} 
 
// 当PHP终止的时候(执行完成或者是遇到致命错误中止的时候)会调用new Shutdown的stop方法 
register_shutdown_function([new Shutdown(), 'stop']); 
 
// 将因为致命错误而中止 
$a = new a(); 
 
// 这一句并没有执行,也没有输出 
echo '必须终止';

也可以在类中执行:

<?php 
 
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' . PHP_EOL; 
 
/** 
运行: 
before 
class TestDemo->f():hello 
 */

4. 同时调用多个

可以多次调用 register_shutdown_function,这些被注册的回调会按照他们注册时的顺序被依次调用。

不过注意的是,如果在第一个注册的中止方法里面调用exit方法或者是die方法的话,那么其他注册的中止回调也不会被调用。
代码:

<?php 
/** 
 * 可以多次调用 register_shutdown_function,这些被注册的回调会按照他们注册时的顺序被依次调用。 
 * 注意:如果你在f方法(第一个注册的方法)里面调用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, "f"], "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的时候,由于类不支持析构函数,所以这个函数经常用来模拟实现析构函数

致命错误的处理:使用该函数可以用来捕获致命错误并且在发生致命错误后恢复流程处理

代码如下:

<?php 
/** 
 * register_shutdown_function,注册一个会在php中止时执行的函数,中止的情况包括发生致命错误、die之后、exit之后、执行完成之后都会调用register_shutdown_function里面的函数 
 * Created by PhpStorm. 
 * User: Administrator 
 * Date: 2017/7/15 
 * Time: 17:41 
 */ 
 
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 '必须终止';

运行:

Fatal error: Uncaught Error: Class 'a' not found in D:\laragon\www\php_book\1_23_register_shutdown.php on line 31 
 
Error: Class 'a' not found in D:\laragon\www\php_book\1_23_register_shutdown.php on line 31 
 
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)来捕获致命错误,代码如下:

<?php 
 
try { 
 // 将因为致命错误而中止 
 $a = new a(); 
 
 // 这一句并没有执行,也没有输出 
 echo 'end'; 
} catch (Throwable $e) { 
 print_r($e); 
 echo $e->getMessage(); 
}

运行:

Error Object 
( 
 [message:protected] => Class 'a' not found 
 [string:Error:private] => 
 [code:protected] => 0 
 [file:protected] => C:\laragon\www\php_book\throwable.php 
 [line:protected] => 5 
 [trace:Error:private] => Array 
  ( 
  ) 
 
 [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范例参考与解析:

<?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也是没办法处理的。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
php中关于普通表单多文件上传的处理方法
Mar 25 PHP
php Hex RGB颜色值互换的使用
May 10 PHP
php中cookie的使用方法
Mar 29 PHP
一个php生成16位随机数的代码(两种方法)
Sep 16 PHP
PHP+jQuery 注册模块开发详解
Oct 14 PHP
Laravel 4 初级教程之视图、命名空间、路由
Oct 30 PHP
php格式输出文件var_export函数实例
Nov 15 PHP
php用户注册时常用的检验函数实例总结
Dec 22 PHP
Yii2使用swiftmailer发送邮件的方法
May 03 PHP
微信公众号开发之文本消息自动回复php代码
Aug 08 PHP
Laravel推荐使用的十个辅助函数
May 10 PHP
PHP cookie与session会话基本用法实例分析
Nov 18 PHP
PHP命令空间namespace及use的用法小结
Nov 27 #PHP
Laravel 批量更新多条数据的示例
Nov 27 #PHP
PHP开发实现微信退款功能示例
Nov 25 #PHP
PHP微信企业号开发之回调模式开启与用法示例
Nov 25 #PHP
PHP递归实现汉诺塔问题的方法示例
Nov 25 #PHP
PHP基于curl post实现发送url及相关中文乱码问题解决方法
Nov 25 #PHP
php图片合成方法(多张图片合成一张)
Nov 25 #PHP
You might like
ftp类(example.php)
2006/10/09 PHP
简单谈谈PHP中的Reload操作
2016/12/12 PHP
jQuery Clone Bug解决代码
2010/12/22 Javascript
jQuery学习笔记之jQuery构建函数的7种方法
2014/06/03 Javascript
jquery中EasyUI实现异步树
2015/03/01 Javascript
jQuery实现的支持IE的html滑动条
2015/03/16 Javascript
Node.js的环境安装配置(使用nvm方式)
2016/10/11 Javascript
AngularJS  双向数据绑定详解简单实例
2016/10/20 Javascript
JavaScript实现事件的中断传播和行为阻止方法示例
2017/01/20 Javascript
JS传参及动态修改页面布局
2017/04/13 Javascript
Angularjs2不同组件间的通信实例代码
2017/05/06 Javascript
Angular.js通过自定义指令directive实现滑块滑动效果
2017/10/13 Javascript
详解webpack3编译兼容IE8的正确姿势
2017/12/21 Javascript
vue页面跳转后返回原页面初始位置方法
2018/02/11 Javascript
原生JS+HTML5实现跟随鼠标一起流动的粒子动画效果
2018/05/03 Javascript
vue+springboot实现项目的CORS跨域请求
2018/09/05 Javascript
关于微信小程序登录的那些事
2019/01/08 Javascript
Angular实现svg和png图片下载实现
2019/05/05 Javascript
微信小程序swiper禁止用户手动滑动代码实例
2019/08/23 Javascript
解决layui-open关闭自身窗口的问题
2019/09/10 Javascript
swiper自定义分页器的样式
2020/09/14 Javascript
通过vue.extend实现消息提示弹框的方法记录
2021/01/07 Vue.js
[28:57]EG vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/16 DOTA
python中的实例方法、静态方法、类方法、类变量和实例变量浅析
2014/04/26 Python
python使用paramiko实现远程拷贝文件的方法
2016/04/18 Python
儿童python练习实例
2018/05/27 Python
Python使用re模块正则提取字符串中括号内的内容示例
2018/06/01 Python
python实现图书借阅系统
2019/02/20 Python
python 使用matplotlib 实现从文件中读取x,y坐标的可视化方法
2019/07/04 Python
Python 3.8正式发布重要新功能一览
2019/10/17 Python
python实现加密的方式总结
2020/01/19 Python
termux中matplotlib无法显示中文问题的解决方法
2021/01/11 Python
css3 盒模型以及box-sizing属性全面了解
2016/09/20 HTML / CSS
社区党员群众路线教育实践活动心得体会
2014/11/03 职场文书
2015年民主生活会发言材料
2014/12/15 职场文书
Java实现添加条码或二维码到Word文档
2022/06/01 Java/Android