【函数】register_shutdown_function函数详解【原创】

今天看书《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:laragonwwwphp_book	est.php on line 12

Error: Class 'a' not found in D:laragonwwwphp_book	est.php on line 12

Call Stack:
    0.0020     360760   1. {main}() D:laragonwwwphp_book	est.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:laragonwwwphp_book1_23_register_shutdown.php on line 31

Error: Class 'a' not found in D:laragonwwwphp_book1_23_register_shutdown.php on line 31

Call Stack:
    0.0060     362712   1. {main}() D:laragonwwwphp_book1_23_register_shutdown.php:0

Begin.
Array
(
    [type] => 1
    [message] => Uncaught Error: Class 'a' not found in D:laragonwwwphp_book1_23_register_shutdown.php:31
Stack trace:
#0 {main}
  thrown
    [file] => D:laragonwwwphp_book1_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:laragonwwwphp_book	hrowable.php
    [line:protected] => 5
    [trace:Error:private] => Array
        (
        )

    [previous:Error:private] =>
    [xdebug_message] =>
Error: Class 'a' not found in C:laragonwwwphp_book	hrowable.php on line 5

Call Stack:
    0.0000     349856   1. {main}() C:laragonwwwphp_book	hrowable.php:0

)
Class 'a' not found


这样的话,PHP7中使用Throwable来捕获的话比使用register_shutdown_function这个函数来得更方便,也更推荐Throwable。
注意:Error类也是可以捕获到致命错误,不过Error只能捕获致命错误,不能捕获异常Exception,而Throwable是可以捕获到错误和异常的,所以更推荐。

总结:register_shutdown_function这个函数主要是用在处理致命错误的后续处理上(PHP7更推荐使用Throwable来处理致命错误),不过缺点也很明显,只能处理致命错误Fatal error,其他的错误包括最高错误Parse error也是没办法处理的。
原文地址:https://www.cnblogs.com/linewman/p/9918110.html