ThinkPHP 8.0迁移需严格遵循三规则:1. 模型中$name必须声明在$table之前,否则报Undefined array key;2. 主键类型须显式定义$pkType为'int'或'string',否则关联查询失效;3. ORM返回null而非false,调用处须增加is_null判断。

将ThinkPHP旧项目中的模型代码迁移到8.0,需直面$name与$table声明顺序、主键类型显式定义、ORM返回值类型变更等硬性约束,不按新规则调整会导致Undefined array key、null返回静默失败、关联查询异常等运行时问题。
修正模型表名声明顺序
TP8模型初始化时严格按声明顺序读取属性:必须先定义【protected $name = 'user'】,再定义protected $table = 'tp_user'。若顺序颠倒或仅定义$table,框架在推导过程中会因未识别$name而触发Undefined array key "table"错误。
打开所有继承think\Model的类文件,定位到属性声明区。
将原有protected $table = 'tp_user';这一行剪切,粘贴到protected $name = 'user';之后——注意两行之间不能有空行或注释隔断。
立即学习“PHP免费学习笔记(深入)”;
若模型未定义$name,则TP8默认用类名小写(如User→user)推导表名;但只要写了$table就必须同步提供$name,否则立即报错。
显式声明主键字段类型
TP8中$model->find(1)或关联查询时,若未声明$pk类型,框架无法自动判断是int还是string,导致关联结果为空或ID匹配失效。
方法一:在模型类中添加protected $pk = 'id';后,紧接一行写protected $pkType = 'int';(对应数字型主键)或protected $pkType = 'string';(对应UUID等字符型主键)。
方法二:直接在构造函数中注入,public function __construct(array $data = []) { parent::__construct($data); $this->pkType = 'int'; }
【不声明$pkType将导致belongsTo关联查不到数据,且无任何报错提示】
适配ORM查询返回值行为
TP8的think-orm 3.0在查不到数据时默认返回null而非抛异常,配合强类型方法签名(如public function getUser(int $id): ?array)极易造成业务逻辑跳过处理分支。
第一步:全局搜索项目中所有模型方法签名,定位含?array、?object、?Model等可空返回类型的函数。
第二步:在调用处增加null判断,例如$user = User::find($id); if (is_null($user)) { throw new HttpException(404, '用户不存在'); }
第三步:检查所有where()->find()链式调用,确认后续代码是否能安全处理null——旧版TP6中find()失败常被当作false处理,而TP8返回的是严格null,=== false判断会失效。
迁移数据库查询语法
TP8废弃Db::name('user')写法,统一改用Db::table('tp_user')。该变更影响所有原生Db操作,包括事务块内、子查询和闭包查询。
打开app/common/db.php或全局Db调用集中文件,批量替换Db::name(为Db::table(。
注意:Db::table('tp_user')->where(...)返回的是Query对象,不再支持TP6中Db::name('user')->where(...)->select()里隐式切换模型上下文的行为——若需模型事件或自动时间戳,必须用User::where(...)->select()。
若存在Db::name('user')->field('id,name')->select()这类写法,直接替换为Db::table('tp_user')->field('id,name')->select()即可,无需额外改动。



















