TP6 + Swoole 是 ThinkPHP 实现 RPC 的唯一稳定路径;需严格遵循 interface/service 规范、执行 rpc:interface 命令生成配置、Swoole 启动服务、避免资源返回及妥善处理异常。

ThinkPHP 实现 RPC 服务接口,关键不在“能不能”,而在“走哪条路”——TP6 + Swoole 是当前唯一稳定、可维护的路径;TP5 的 RpcController 已淘汰且无官方维护,强行复用会掉进协议兼容、超时控制、连接复用等深坑。
TP6 中必须用 interface + service 类组合
不是为了“面向接口编程”的教条,而是 think\swoole\rpc\server\Dispatcher::prepareServices() 在启动时硬性扫描并注册服务,只认 implements 某个 interface 的类。直接写个普通类加注解或配置,服务根本不会被发现。
- interface 必须定义在
app\rpc\interfaces\下(路径可配,但需与rpc:interface命令生成逻辑一致) - service 类必须
implements该 interface,且方法签名(参数名、类型提示、返回类型)必须完全一致 - interface 中不能有默认实现,也不能含
static或private方法 —— 否则客户端生成失败或调用报错Call to undefined method
客户端调用前必须执行 php think rpc:interface
这个命令不是“可选步骤”,它负责两件事:解析服务端 interface 并生成 app/rpc.php,同时把每个服务映射到对应命名空间。没这步,Container::get('userservice') 或 make(UserInterface::class) 都会找不到绑定。
- 生成的
rpc.php文件不能手动修改 —— 下次再执行该命令会被覆盖 - 如果改了 interface 方法签名,必须重新运行该命令,否则客户端缓存的代理类仍按旧签名调用,报错如
Too few arguments to function ... - 若服务端部署在其他机器,
host和port要在config/swoole.php的'client' => ['userservice' => [...]]里配对,而非写死在 interface 中
服务端启动必须用 php think swoole start
php -S 或 FPM 模式下跑不了 TP6 的 RPC 服务 —— 因为底层依赖 Swoole 的 TCP server、协程上下文和长连接管理。直接访问 HTTP URL 触发 RpcController 是 TP5 的老方案,TP6 已移除该机制。
立即学习“PHP免费学习笔记(深入)”;
- 启动前确认
swoole.enable_coroutine = On且extension=swoole已加载(用php --ri swoole验证) - 端口被占用时,错误信息是
Address already in use,但日志可能只显示Server start fail—— 建议先lsof -i :9000(Linux/macOS)或netstat -ano | findstr :9000(Windows)查端口 - 修改了 service 类代码后,必须重启 Swoole 进程(
php think swoole restart),热重载不生效
RPC 接口不能直接返回资源型数据(如 file_get_contents() 结果、GD 图像资源)
Swoole 的序列化机制不支持 PHP 资源(resource),强行返回会导致客户端收到空值或 Serialization of 'resource' is not allowed 错误。
- 文件内容统一转为字符串或 base64 编码后再返回
- 数据库查询结果应使用
toArray()或jsonSerialize()显式转换,避免传递 Query 对象或 PDOStatement - 如果需要流式传输大文件,不要走 RPC,改用 HTTP 下载接口 + token 鉴权更稳妥
真正容易被忽略的是服务端异常处理 —— try/catch 里抛出的 Exception 默认会被吞掉,客户端只收到空响应或超时。必须在 service 方法内显式 return ['error' => 'xxx'],或统一拦截 think\swoole\rpc\server\Dispatcher 的异常钩子。这点没有文档强调,但线上故障十有八九出在这儿。



















