ThinkPHP3.2.3 升级 ThinkPHP8.1 实战指南

yvsm4个月前PHP11600

从 ThinkPHP3.2.3 跳跃升级至 ThinkPHP8.1,核心难点在于底层 API、语法规范、目录结构的大幅变更。本文覆盖控制器、模型、路由、验证、数据库操作等核心模块,通过“TP3.2.3 旧代码 vs TP8.1 新代码”的对比形式,直观呈现升级要点,助力开发者快速落地修改。

前置说明:升级前需完成 3 件事① 备份代码与数据库,创建独立升级分支;② 部署 PHP8.0+ 环境(推荐 PHP8.1),安装最新版 Composer;③ 新建 TP8.1 项目(composer create-project topthink/think tp81-project),后续将 TP3.2.3 核心代码迁移至新项目并修改。

一、目录结构与入口文件修改

TP3.2.3 与 TP8.1 目录结构差异显著,需先完成基础目录迁移与入口文件调整,确保项目可正常访问。

1. 目录迁移核心规则

TP3.2.3 目录/文件TP8.1 对应目录/文件关键说明
Application/app/模块(如 Home、Admin)直接迁移至 app/,目录名小写(推荐)
Application/Common/Conf/config/公共配置迁移至 config/ 目录,按 TP8.1 文件名规范重命名(如 config.php、database.php)
index.php(根目录)public/index.php替换为 TP8.1 入口文件,Web 服务器根目录指向 public/

2. 入口文件代码修改示例

TP3.2.3 根目录 index.php(旧代码):

<?php
// 定义应用目录
define('APP_PATH', './Application/');
// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';

TP8.1 public/index.php(新代码,直接使用框架默认入口文件,无需修改核心逻辑):

<?php
// [ 应用入口文件 ]
namespace think;

// 加载基础文件
require __DIR__ . '/../vendor/autoload.php';

// 执行应用并响应
$http = (new App())->http;

$response = $http->run();

$response->send();

$http->end($response);

二、控制器代码修改:命名空间与继承适配

TP3.2.3 控制器无强制命名空间要求,继承 Think\Controller;TP8.1 需严格遵循命名空间规范,继承think\Controller,同时支持依赖注入。

核心修改示例:基础控制器

TP3.2.3 Application/Home/Controller/IndexController.php(旧代码):

<?php
namespace Home\Controller;
use Think\Controller;

class IndexController extends Controller {
    // 首页方法
    public function index() {
        // 接收参数
        $id = I('get.id', 0, 'intval');
        // 渲染模板
        $this->assign('id', $id);
        $this->display();
    }
}

TP8.1 app/controller/Index.php(新代码):

<?php
namespace app\controller;
use think\Controller;
use think\facade\Request; // 引入请求类

class Index extends Controller {
    // 首页方法(支持依赖注入,如注入Request对象)
    public function index(Request $request) {
        // 接收参数(替代I()函数)
        $id = $request->get('id', 0, 'intval');
        // 渲染模板(模板目录调整至 view/ 下)
        return $this->fetch('index', ['id' => $id]);
    }
}

关键修改点:① 命名空间统一为 app\controller;② 接收参数使用 think\facade\Request 替代 I() 函数;③ 渲染模板用 fetch() 替代 display(),模板目录迁移至 view/[模块名]/ 下。

三、模型代码修改:ORM 与软删除适配

TP8.1 依赖 think-orm 3.0+,模型的时间戳处理、软删除逻辑、关联查询语法与 TP3.2.3 差异极大,需重点重构。

1. 基础模型修改示例

TP3.2.3 Application/Home/Model/UserModel.php(旧代码):

<?php
namespace Home\Model;
use Think\Model;

class UserModel extends Model {
    // 表名(默认无需指定,按规则匹配)
    protected $tableName = 'user';
    // 自动完成(时间戳)
    protected $_auto = [
        ['create_time', 'time', self::MODEL_INSERT, 'function'],
        ['update_time', 'time', self::MODEL_BOTH, 'function'],
    ];
    // 软删除配置
    protected $deleteTime = 'delete_time';
}

TP8.1 app/model/User.php(新代码):

<?php
namespace app\model;
use think\Model;
use think\model\concern\SoftDelete; // 引入软删除Trait

class User extends Model {
    // 表名(若与模型名不一致需指定)
    protected $name = 'user';
    // 时间戳字段(显式声明,默认自动写入)
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    // 软删除配置(替代TP3.2.3的$deleteTime)
    use SoftDelete;
    protected $deleteTime = 'delete_time';
    protected $defaultSoftDelete = 0; // 软删除标识(0=未删除,非0=删除时间戳)
}

2. 关联查询修改示例

TP3.2.3 模型关联(旧代码):

// UserModel 中定义关联
public function order() {
    // 一对一关联:用户对应一个订单
    return $this->hasOne('OrderModel', 'user_id', 'id');
}

// 控制器中调用
$user = D('User')->find(1);
$orderInfo = $user->order;

TP8.1 模型关联(新代码):

// User 模型中定义关联
use app\model\Order; // 引入关联模型

public function order() {
    // 一对一关联,语法更严格
    return $this->hasOne(Order::class, 'user_id', 'id');
}

// 控制器中调用(需通过with()预加载,提升性能)
use app\model\User;

$user = User::with('order')->find(1);
$orderInfo = $user->order;

四、路由配置修改:从自动匹配到显式定义

TP3.2.3 支持 URL 自动匹配模块/控制器/方法,TP8.1 强化路由功能,推荐显式定义路由,同时正则写法需调整。

核心修改示例

TP3.2.3 路由(无单独配置文件,依赖自动匹配,或在 Application/Common/Conf/config.php 中简单配置):

'URL_ROUTE_RULES' => [
    // 路由规则:/user/:id 对应 Home/UserController/info 方法
    'user/:id' => 'Home/User/info',
    // 带正则约束的路由
    'article/:id\d' => 'Home/Article/detail',
]

TP8.1 路由(配置文件 config/route.php,新代码):

<?php
use think\facade\Route;

// 路由规则:/user/:id 对应 app/controller/User.php 的 info 方法
Route::get('user/:id', 'User/info')->rule([
    'id' => '\d+' // 正则约束(替代TP3.2.3的\d后缀)
]);

// 带参数验证的路由(新增特性)
Route::get('article/:id', 'Article/detail')
    ->rule(['id' => '\d+'])
    ->when(['id' => '>0'], '文章ID必须大于0'); // 路由变量验证

// 路由分组(新增特性,便于管理)
Route::group('admin', function() {
    Route::get('login', 'Admin/login');
    Route::get('dashboard', 'Admin/dashboard');
})->middleware('Auth'); // 绑定中间件

关键修改点:① 路由配置集中至 config/route.php;② 用 Route::get/post() 显式声明请求方式;③ 正则约束通过 rule() 方法定义,移除 TP3.2.3 的 URL 后缀约束;④ 新增路由分组、中间件绑定、参数验证等特性。

五、验证逻辑修改:从函数验证到验证类

TP3.2.3 常用 D() 函数或 Think\Verify 进行验证,TP8.1 推荐使用独立验证类,扩展了更多验证规则。

核心修改示例

TP3.2.3 验证逻辑(旧代码,写在控制器中):

public function add() {
    if (IS_POST) {
        $data = I('post.');
        // 验证规则
        $rules = [
            ['username', 'require', '用户名不能为空'],
            ['password', '6,20', '密码长度必须在6-20位之间'],
            ['email', 'email', '邮箱格式错误'],
        ];
        $user = D('User');
        if (!$user->validate($rules)->create($data)) {
            $this->error($user->getError());
        }
        // 数据入库...
    }
}

TP8.1 验证逻辑(新代码,独立验证类+控制器调用):

1. 新建验证类 app/validate/User.php:

<?php
namespace app\validate;
use think\Validate;

class User extends Validate {
    // 验证规则
    protected $rule = [
        'username' => 'require|chsAlphaNum', // 新增汉字字母数字验证
        'password' => 'require|length:6,20',
        'email' => 'require|email',
    ];
    // 错误提示
    protected $message = [
        'username.require' => '用户名不能为空',
        'username.chsAlphaNum' => '用户名只能是汉字、字母或数字',
        'password.require' => '密码不能为空',
        'password.length' => '密码长度必须在6-20位之间',
        'email.email' => '邮箱格式错误',
    ];
    // 场景验证(新增特性,按需验证)
    protected $scene = [
        'add' => ['username', 'password', 'email'], // 新增场景需验证所有字段
        'edit' => ['username'], // 编辑场景仅验证用户名
    ];
}

2. 控制器中调用验证类:

use app\validate\User as UserValidate;
use think\facade\Request;

public function add() {
    if (Request::isPost()) {
        $data = Request::post();
        // 实例化验证类并指定场景
        $validate = new UserValidate();
        if (!$validate->scene('add')->check($data)) {
            $this->error($validate->getError());
        }
        // 数据入库(可通过模型实例化入库)
        $user = new \app\model\User();
        $user->save($data);
        $this->success('新增成功');
    }
}

六、数据库操作修改:从 M()/D() 到 ORM 方法

TP3.2.3 常用 M()(简单模型)、D()(自定义模型)操作数据库,TP8.1 推荐使用 ORM 方法或查询构造器,废弃 M()/D() 函数。

核心修改示例

TP3.2.3 数据库操作(旧代码):

// 1. 用M()函数查询
$userList = M('User')
    ->where('status', 1)
    ->where('create_time', '>', strtotime('-7 day'))
    ->order('id desc')
    ->limit(10)
    ->select();

// 2. 用D()函数新增数据
$user = D('User');
$data = [
    'username' => 'test',
    'password' => md5('123456'),
    'create_time' => time(),
];
$user->add($data); // 新增数据

// 3. 闭包查询
$list = M('Article')
    ->where(function($query) {
        $query->where('cat_id', 1)->orWhere('is_top', 1);
    })
    ->select();

TP8.1 数据库操作(新代码):

use app\model\User;
use app\model\Article;
use think\facade\Db; // 或使用Db门面

// 1. 模型查询(推荐)
$userList = User::where('status', 1)
    ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('-7 day'))) // 需传递标准时间格式
    ->order('id', 'desc')
    ->limit(10)
    ->select();

// 2. 模型新增数据(自动处理时间戳)
$user = new User();
$user->save([
    'username' => 'test',
    'password' => password_hash('123456', PASSWORD_DEFAULT), // 推荐使用password_hash
]);

// 3. 闭包查询(语法更严格)
$list = Article::where(function($query) {
    $query->where('cat_id', 1)->whereOr('is_top', 1); // orWhere改为whereOr
})
->select();

// 4. 用Db门面操作(适合复杂查询)
$list = Db::table('article')
    ->where(function($query) {
        $query->where('cat_id', 1)->whereOr('is_top', 1);
    })
    ->select();

七、常见报错与代码修复对照表

升级后常见报错报错原因修复代码示例
Call to undefined function I()TP8.1 废弃 I() 函数用 Request 门面替代:$id = I('get.id')$id = Request::get('id')
Class 'Think\Controller' not found命名空间变更use 语句修改:use Think\Controlleruse think\Controller
Invalid datetime format: 1292 Incorrect datetime value时间戳格式不匹配传递标准时间格式:time()date('Y-m-d H:i:s')
Route not found路由未显式定义或正则格式错误在 config/route.php 中定义路由,正则移除斜杠:regex:/\d+/regex:\d+

八、升级收尾:测试与优化

1. 全量测试:重点测试路由访问、数据增删改查、核心业务(登录、支付、上传)、兼容性(PHP8.1~8.4);2. 性能优化:执行 php think optimize:schema 生成数据库结构缓存,开启 Redis 缓存提升性能;3. 安全优化:检查文件权限(public 目录可写,其他目录只读),替换 md5 加密为 password_hash 加密。

相关文章

ThinkPHP8.X模型关联详解

在ThinkPHP框架中,模型关联是处理数据表数据表之间关系的重要机制。通过模型关联,我们可以方便地操作具有关联关系的数据,如一对一、一对多、多对多等关系。本文将详细介绍ThinkPHP中常见的模型关...

ThinkPHP 8 性能优化实战:从 2s 到 200ms 的蜕变

最近接手了一个 ThinkPHP 8 项目,首页加载竟然要 2 秒多。经过一周的深度优化,最终稳定在 200ms 以内。这篇文章分享我的优化思路和实战经验。一、问题诊断:找到性能瓶颈优化之前,先用工具...

ThinkPHP5.0.24 升级 ThinkPHP8.1 实战指南

从 ThinkPHP5.0.24 升级至 ThinkPHP8.1,虽无 TP3 升级的跨度大,但核心差异体现在命名空间规范、ORM 语法、路由机制、验证体系及 PHP 版本兼容(TP8 要求 PHP8...

在 PHP 中写真正的异步代码 TrueAsync 0.6.0 已支持数据库链接池

在 PHP 中写真正的异步代码 TrueAsync 0.6.0 已支持数据库链接池 现代软件的构建最终仍然要回到实践。再复杂的产品,也必须经过真实用户的检验。只有最终用户,才能真正区分哪些设计是有...

ThinkTemplate 模板引擎完全指南

ThinkTemplate 模板引擎完全指南ThinkTemplate 是 ThinkPHP 的内置模板引擎,现已支持独立使用。本文详细介绍其核心特性和使用方法。环境要求ThinkTemplate 3...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。