thinkphp跨大版本升级需分步验证环境、依赖与代码兼容性。先确认php≥8.0且cli/web sapi版本一致,检查必需扩展;再通过composer更新依赖,清理runtime缓存;最后适配目录结构、facade调用、路由定义及中间件等变更。

ThinkPHP 升级不是改个版本号就能跑通的事,尤其是跨大版本(比如 6→8),必须分步验证环境、依赖、代码兼容性,否则上线就报错。
确认当前版本和 PHP 环境是否达标
很多升级失败,其实卡在第一步:你根本没看清自己站在哪,就急着跳。执行 php think version 查当前框架版本,同时用 php -v 和 phpinfo()(或 php -m | grep fpm)确认 CLI 和 Web SAPI 的 PHP 版本是否一致——ThinkPHP 8.0 要求 PHP ≥ 8.0.0,而很多服务器上 CLI 是 8.1,但 Nginx 跑的是 7.4 的 php-fpm,这种“双版本陷阱”会导致 composer update 成功、浏览器访问直接 500。
- 不光看 PHP 主版本,还要检查扩展:
mbstring、openssl、pdo_mysql、json必须启用 - 如果项目用了
topthink/think-multi-app或topthink/think-swoole,这些扩展在 TP8 中可能已废弃或需单独适配 - 建议先在本地搭一个干净的
php:8.2-apacheDocker 环境跑验证,比修生产服务器快得多
用 Composer 替换核心依赖,别手动拷文件
手动下载 ZIP 包、覆盖 thinkphp/ 目录是 ThinkPHP 3.x/5.x 的老办法,TP6 起全面 Composer 化,硬拷会导致 autoloader 错乱、类找不到、甚至 Class 'think\App' not found 这种致命错误。
- 打开
composer.json,把"topthink/framework": "^6.0"改成"topthink/framework": "^8.0" - 运行
composer update topthink/framework --with-all-dependencies(加--with-all-dependencies防止子依赖冲突) - 如果提示
your requirements could not be resolved,说明其他包(如monolog、psr/log)版本太旧,得一并升级,不要跳过 - 升级后别忘了删掉
runtime/目录——缓存残留常导致路由/配置读取旧逻辑
检查 config/ 和 app/ 下的硬编码调用
TP8 彻底移除了 application/ 目录结构,统一为 app/ + config/,而且大量 Facade 类行为变更。最典型的坑是:
立即学习“PHP免费学习笔记(深入)”;
-
Request::instance()已废弃,改用think\facade\Request或注入think\Request -
Db::name('user')->where(...)->select()仍可用,但Db::table('user')在某些场景下会绕过模型事件,TP8 更推荐用模型操作 - 自定义的
common.php若放在app/common.php,需确认是否被自动加载(TP8 默认只加载app/Helper.php) - 路由定义从
route/route.php移到app/Route.php,且语法微调:Route::get('user', 'index/user/index')要改成Route::get('user', [app\controller\Index::class, 'user'])
测试时重点盯住中间件、事件和数据库查询构造器
TP8 对中间件生命周期、事件监听器注册方式做了收敛,表面没报错,但登录态丢失、日志不写入、钩子不触发这类“静默失效”最难排查。
- 检查
app/middleware.php是否还存在——TP8 已改为在app/Middleware.php中返回数组,且中间件类必须实现think\contract\MiddlewareInterface -
Db::query()执行原生 SQL 时,TP8 默认开启预处理,若 SQL 里含?占位符又没传参数,会直接抛异常而不是静默忽略 - 如果你用了软删除(
SoftDeletetrait),确认模型里是否显式声明了protected $deleteTime = 'delete_time';,TP8 不再自动推断字段名 - 单元测试若用
Mockery模拟 Facade,要改用think\testing\TestCase基类,否则容器绑定失效
真正麻烦的从来不是命令敲几行,而是那些没报错却逻辑偏移的地方:比如时间字段自动转换、JSON 字段序列化方式变化、或者视图中 {:url('index/index')} 生成的 URL 少了一级路径——这些都得靠真实请求路径逐条过,不能只信 PHPUnit。











