defer 是协程级延迟执行,finally 是语句块级异常保障;defer 绑定协程生命周期,协程退出必执行,按 LIFO 顺序调用;finally 仅限当前 try 块,异常未捕获则跳过;defer 适合协程资源释放,finally 适合单次操作兜底。

defer 是协程级延迟执行,finally 是语句块级异常保障
两者都用于收尾清理,但作用域、触发时机和适用场景完全不同。defer 绑定在当前协程生命周期上,只要协程退出(无论正常 return 还是抛出未捕获异常),它就一定执行;finally 只绑定在对应 try-catch 语句块内,仅当该语句块执行完毕时才运行,不跨函数、不跨协程。
协程退出时 defer 一定会执行,finally 可能根本没机会跑
这是最常踩的坑:在协程里 throw 异常后,如果外层没套 try-catch,协程会立即终止,此时函数体内写在 try 外的 finally 根本不会进入——但所有已注册的 Co::defer() 仍会执行。
-
Co::defer()注册的回调,在协程结束前统一按 LIFO(后进先出)顺序调用,哪怕exit()或致命错误也会触发 -
finally只对当前try块负责;若异常未被当前函数 catch,控制流直接跳出函数,finally被跳过 - 常见误用:在
go(function() { ... })里只写finally关数据库连接,结果协程因未捕获异常提前退出,连接泄漏
defer 更适合资源自动释放,finally 更适合局部逻辑兜底
选哪个,关键看你要保护的是「协程资源」还是「单次操作完整性」。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 用
Co::defer():关闭文件句柄、释放连接池实例、清理临时目录、记录协程耗时统计 —— 这些跟协程生命周期强绑定 - 用
finally:确保某次 Redismulti()操作要么全提交要么全 discard,或保证某次 HTTP 请求无论成功失败都记录日志 —— 与具体业务逻辑耦合紧密 - 二者可共存:一个协程里既注册
Co::defer()做连接回收,又在关键 I/O 操作周围加try-finally做原子性保障
defer 不替代 try-catch,异常仍需显式捕获
Co::defer() 不处理异常,它只做清理。协程内未 catch 的异常依然会中断执行流,并可能触发 Fatal error: Uncaught RuntimeException —— 这和 finally 是否存在无关。
- 每个协程函数体开头必须自己
try-catch,父协程无法捕获子协程异常 -
Co::defer()在catch块里注册也有效,且会在catch执行完后触发 - 不要指望
defer来“兜住”异常逻辑,它不介入错误传播链,只守最后一道资源防线
真正容易被忽略的点是:协程里写 defer 很 cheap,但忘了配 try-catch 就等于把异常交给 Swoole 默认处理器——它只会打 log 然后静默 kill 协程,你连错误上下文都捞不到。

















