Coroutine::defer
最后更新于:2022-04-02 06:25:54
# Coroutine::defer
[TOC]
> 需要Swoole版本 >= 4.2.9
>
> 该方法拥有一个短名:`defer`
`defer`用于资源的释放, 会在**协程关闭之前**(即协程函数执行完毕时)进行调用, 就算抛出了异常, 已注册的`defer`也会被执行.
需要注意的是, 它的调用顺序和`go`语言中的`defer`一样是逆序的(先进后出), 也就是先注册`defer`的后执行, 在底层`defer`列表是一个`stack`, 先进后出. 逆序符合资源释放的正确逻辑, 后申请的资源可能是基于先申请的资源的, 如先释放先申请的资源, 后申请的资源可能就难以释放。
与`Go`语言不同的是`Swoole4`的`defer`是协程退出前执行。这是因为`Go`没有提供析构方法,而`PHP`对象有析构函数,使用`__destruct`就可以实现`Go`的`defer`特性,参见[如何实现 Go defer](协程:实现Go语言风格的defer.md)。
## 示例
> Context为用户自己实现的协程上下文管理器
~~~
go(function () {
$info = Context::get('info', Co::getuid()); // get context of this coroutine
defer(function () {
Context::delete('info', Co::getuid()); // delete
});
throw new Exception('something wrong');
echo "never here\n";
});
~~~
## Context
~~~
use Swoole\Coroutine;
class Context {
protected static $pool = [];
public static function cid():int {
return Coroutine::getuid();
}
public static function get($key, int $cid = null) {
$cid = $cid ?? Coroutine::getuid();
if ($cid < 0) {
return null;
}
if (isset(self::$pool[$cid][$key])) {
return self::$pool[$cid][$key];
}
return null;
}
public static function put($key, $item, int $cid = null) {
$cid = $cid ?? Coroutine::getuid();
if ($cid > 0) {
self::$pool[$cid][$key] = $item;
}
return $item;
}
public static function delete($key, int $cid = null) {
$cid = $cid ?? Coroutine::getuid();
if ($cid > 0) {
unset(self::$pool[$cid][$key]);
}
}
public static function destruct(int $cid = null) {
$cid = $cid ?? Coroutine::getuid();
if ($cid > 0) {
unset(self::$pool[$cid]);
}
}
}
~~~
';