mostka / defer
defer 函数将函数的执行推迟到外围函数返回时再执行。
2.0.2
2024-08-29 07:18 UTC
Requires
- php: >=8.1
Requires (Dev)
- phpunit/phpunit: ^10.5
README
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();