🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 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]); } } } ~~~