thinkphp8新特性需按需使用:多应用绑定须用App::getInstance()->bind()或Container::getInstance()->bind();协程需php think swoole启动并启用enable_coroutine;嵌套事务须显式传true且引擎为InnoDB;模板默认禁用PHP表达式,需配置tpl_deny_php或改用{php}标签。

ThinkPHP8 的新特性不是拿来“学”的,而是为了解决具体问题才用的——比如你正被多应用路由混乱困扰,或想让命令行任务支持协程,那才值得动它。
多应用模式下 app()->bind() 失效怎么办
TP8 把应用生命周期和容器解耦了,app()->bind() 在非主应用里大概率不生效,因为绑定发生在主应用容器,子应用拿不到。
- 改用
App::getInstance()->bind()显式获取当前应用实例再绑定 - 更稳妥的做法是:在子应用的
bootstrap.php里调用Container::getInstance()->bind() - 别在全局
common.php里写 bind,那里没应用上下文,绑定后可能被后续应用覆盖
为什么 think run 启动不了协程服务
TP8 默认命令行不启用协程支持,think run 走的是传统 Swoole http server 启动流程,不是 swoole_http_server 或 corun。
- 必须手动安装
swoole扩展(v5.0+),且 PHP 编译时不能禁用--enable-coroutine - 启动命令要换成
php think swoole,并确保配置中'swoole' => ['enable_coroutine' => true] - 协程内不能用
sleep()、file_get_contents()等同步阻塞函数,得换co::sleep()、co::readFile()
Db::transaction() 嵌套事务在 TP8 里怎么写才不报错
TP8 的事务底层改用 pdo 的 savepoint 实现嵌套,但默认不开启,直接嵌套会抛出 RuntimeException: Transaction already started。
立即学习“PHP免费学习笔记(深入)”;
- 外层事务必须显式传
true:Db::transaction(fn() => ..., true) - 内层用
Db::transactionLevel()判断当前层级,避免重复 commit/rollback - 注意 mysql 必须是 InnoDB 引擎,且隔离级别不能是
READ UNCOMMITTED,否则 savepoint 无效
模板引擎升级后 {:func()} 语法突然不解析了
TP8 模板编译器默认关闭了 PHP 表达式执行(tpl_deny_php 默认为 true),{:func()} 这类动态调用会被直接忽略或报错。
- 临时方案:在
config/template.php中设'tpl_deny_php' => false(仅开发环境) - 推荐做法:把逻辑提到控制器,用
assign()传变量,模板里只做展示 - 如果真要保留表达式,改用
{php}echo func();{/php},但需确认tpl_replace_string配置未禁用php标签
TP8 的改动大多藏在容器初始化时机、协程适配边界、以及模板/数据库这类高频模块的默认策略里。最容易被忽略的,是那些“以前能跑,现在不报错但结果不对”的情况——比如事务没回滚成功、协程里用了静态变量、或者模板变量作用域意外泄漏。