ThinkPHP 8.0 是基于 PHP 8.0+ 的底层重构框架,非 TP5.1 或 TP6.0 的简单升级;必须强制使用 PHP ≥8.0,全面遵循 PSR-14/PSR-15 标准,废弃 think\Request 等私有类,要求中间件实现 MiddlewareInterface、模型启用强类型、路由/事件/配置均按新范式重写。

ThinkPHP 8.0 不是 TP6 的简单升级,而是彻底重构的现代 PHP 框架,和 TP5.1、TP6.0 在底层设计、依赖、语法习惯上存在断裂式差异——如果你正用 TP5.1 或 TP6.0 迁移项目,别指望“改几行就能跑”,得按新范式重写核心逻辑。
TP5.1 是经典 MVC,TP6 是过渡态,TP8 是 PSR-14/PSR-15 原生玩家
TP5.1 基于自研路由+控制器生命周期,App::run() 启动即执行;TP6 引入了 think\Container 和基础中间件支持,但中间件链仍绕不开框架封装层;TP8 则完全基于 psr/http-server-middleware,所有中间件必须实现 MiddlewareInterface,$next($request) 成为标准调用方式。这意味着你写的中间件在 TP6 里能跑,在 TP8 里直接报 TypeError: Argument 1 passed to ... must be an instance of Psr\Http\Message\ServerRequestInterface。
- TP5.1 默认不校验 PSR 标准,
Request对象是框架私有类 - TP6 开始提供
Psr7Request适配器,但默认不启用,需手动配置'psr' => true在config/app.php - TP8 移除了所有非 PSR 请求/响应对象,
think\Request已不存在,只保留think\http\Request(它就是Psr\Http\Message\ServerRequestInterface实现)
TP8 要求 PHP 8.0+,不是“建议”,是硬性编译级依赖
TP8 大量使用 PHP 8.0 新特性:联合类型(string|int|null)、构造函数属性提升(public function __construct(protected Container $container) {})、match 表达式、以及 Attribute 原生注解(用于路由绑定和验证规则)。你在 PHP 7.4 下 composer require thinkphp/framework 就会失败,报错:Your requirements could not be resolved to an installable set of packages. —— 因为 composer.json 中明确写了 "php": "^8.0"。
- TP5.1 支持 PHP 5.6–7.4(已停止维护)
- TP6.0 要求 PHP 7.1+,最高兼容 PHP 8.1(但未用任何 8.x 特性)
- TP8.0 最低要求 PHP 8.0,且已适配 PHP 8.3(如
#[\Override]注解用于核心类重写)
模型层:TP5.1/TP6 的 Db::table() 在 TP8 里不推荐直用
TP8 的 think\Model 彻底去除了静态代理模式,Db::name('user')->where(...)->select() 依然可用,但不再推荐——因为 Db 类本身已被标记为 @deprecated,官方文档明确建议“优先使用模型实例或 Query 对象”。更关键的是,TP8 的模型默认开启强类型检查,字段映射失败时会抛出 think\model\exception\ModelNotFoundException,而 TP5.1/TP6 只是静默忽略。
立即学习“PHP免费学习笔记(深入)”;
- TP5.1 中
UserModel::get(1)返回 null 或对象,无类型约束 - TP6 中可配置
'model_force' => true启用严格模式,但非默认 - TP8 中
UserModel::findOrFail(1)是首选,find()返回?UserModel(可空联合类型),IDE 和 PHPStan 能静态识别 - TP8 的
withJoin()替代了 TP6 的withAttr()+ 手动关联,语法更接近 Laravel 的with(['profile', 'posts' => function ($q) { ... }])
迁移最易卡住的三个点:路由定义、事件监听、配置加载
TP8 把路由注册从 route/route.php 搬到了 app/bootstrap.php 中的 Route::import() 调用;事件系统从 Event::trigger() 改为 PSR-14 兼容的 EventManager::dispatch(),监听器必须实现 ListenerInterface;配置不再自动合并 config/*.php,而是靠 Config::load() 显式加载,且环境配置(.env)优先级高于 PHP 文件。
- TP5.1/TP6 的
route::rule('user/:id', 'index/user/read')在 TP8 必须写成Route::get('user/{id}', [UserController::class, 'read']) - TP6 的
event('user_login', $data)在 TP8 得先$event = new UserLoginEvent($user),再event($event) - TP8 的
config('database.hostname')读不到database.php里的值,除非你已在app/bootstrap.php中调用Config::load('database')
TP8 的“现代化”不是加功能,是砍掉历史包袱换来的可维护性——但代价是你得重读文档里每个接口的类型签名,而不是扫一眼示例就开干。尤其注意 think\facade\* 门面类在 TP8 中多数只是对 PSR 接口的轻量包装,它们的返回值类型比 TP6 更严格,IDE 提示更准,但也更容易因类型不匹配提前报错。



















