mostka/defer

defer 函数将函数的执行推迟到外围函数返回时再执行。

2.0.2 2024-08-29 07:18 UTC

This package is auto-updated.

Last update: 2024-09-10 14:34:21 UTC


README

Tests Coverage Status

php-defer

PHP 对 Go 中的 defer 语句的实现

PHP defer 函数安排在执行 defer 的函数返回之前立即执行函数调用(延迟函数)。这是一种处理必须释放的资源(无论函数返回路径如何)的不寻常但有效的方法。典型例子是解锁互斥锁或关闭文件。

// Contents returns the file's contents as a string.
function contents($filename) {
    $f = fopen($filename, "r");
    if ($f === false) {
        throw new Exception("Error opening the file");
    }
    $defer = defer(fclose(...),$f);  // fclose will run when we're finished.

    $result = ""; 

    while (($buffer = fread($f, 100)) !== false) {
        $result .= $buffer; 
    }

    if (feof($f) === false) {
        // $f will be closed if we return here.
        throw new Exception("Error reading the file");
    }

    // $f will be closed if we return here.
    return $result;
}

延迟调用 Close 等函数有两个优点。首先,它保证您永远不会忘记关闭文件,这很容易在稍后编辑函数以添加新返回路径时发生。其次,它意味着关闭操作靠近打开操作,这比将其放置在函数末尾更清晰。

安装

composer require tito10047/defer 

快速示例

function foo($a){
    echo "in defer {$a}".PHP_EOL;
}
function a() {
    echo "before defer".PHP_EOL;
    $defer = defer(foo(...),1);
    $defer(foo(...),2);
    $defer(foo(...),3);
    echo "after defer".PHP_EOL;
};

echo "start".PHP_EOL;
a();
echo "end".PHP_EOL;

将打印

start
before defer
after defer
in defer 3
in defer 2
in defer 1
end

3 条规则

defer 语句的行为简单直接且可预测。有三个简单规则

1. 延迟函数的参数在 defer 语句评估时进行评估。

在这个例子中,当 printf 调用被延迟时,表达式 "i" 被评估。延迟调用将在函数返回后打印 0

function a(){
    $i=0;
    $_ = defer(printf(...),$i);
    $i++;
}

将打印 000

2. 延迟函数调用在外围函数返回后按后进先出顺序执行。

这个函数打印 3210

function b(){
    $defer = defer();
    for($i=0;$i<4;$i++){
        $defer(printf(...),$i);
    }
}

3. 当是类型时,延迟函数不能修改返回值,但可以修改数组的引用或对象的引用的内容。

在这个例子中,延迟函数在函数返回后递增 increment $o->i,但不修改返回的 $i。这个例子打印 2-3

function c() {
    $i=1;
    $o=new \stdClass();
    $o->i=2;
    $defer = defer(function () use (&$i, $o) {
        $o->i++;
        $i++;
    });

    $i++;
    return [$i,$o];
}
list($i,$o) = c();
echo "{$i}-{$o->i}".PHP_EOL;

PHP 限制

  • 在 php defer 实现中,您不能修改返回值。只能修改返回引用的内容
  • 在使用之前需要实例化 defer 对象,使用 $defer = new Defer()$defer = defer()

用法

namespace test;

require_once __DIR__.'/../vendor/autoload.php';

function myFunc(){}
class Foo{
    public function myMethod(){}
}
function a(){
    // defer custom function without parameter
    // function name must be with his namespace
    $defer = defer('test\myFunc');
    // defer function with one parameter
    $defer(printf(...),"test");
    // defer function with more parameters
    $defer('printf',"%s-%s",10,12);
    // defer with anonymous function
    $defer(function (){});
    $func = function (){};
    $defer($func);
    //defer method
    $foo = new Foo();
    $defer([$foo,'myMethod']);
}
a();