PHP ThinkPHP 框架入门

ThinkPHP 是国内最流行的 PHP 框架,文档完善、中文友好,适合快速开发。ThinkPHP 6 基于 PHP 7.2+,采用单应用和多应用模式,内置了路由、ORM、模板引擎、缓存、队列等完整的 Web 开发组件。对于国内开发者来说,ThinkPHP 的中文文档和活跃的社区是其最大优势。

安装

ThinkPHP 通过 Composer 安装,think 命令行工具提供了代码生成、服务器启动等便捷功能。

BASH 实例
# 需要先安装 Composer
composer create-project topthink/think myapp
cd myapp
php think run  # 启动内置服务器
``

访问 http://localhost:8000 看到欢迎页即安装成功。

安装完成后,建议立即修改 .env 文件配置数据库连接信息,并将 APP_DEBUG 设为 false(生产环境)。ThinkPHP 6 默认使用单应用模式,如果需要多模块(如前台、后台、API),可以通过 php think build 命令切换到多应用模式。

目录结构

ThinkPHP 6 的目录结构清晰,遵循关注点分离原则,各类文件有明确的存放位置。

` myapp/ ├── app/ │ ├── controller/ # 控制器 │ ├── model/ # 模型 │ └── view/ # 视图 ├── config/ # 配置文件 ├── public/ # 网站根目录(入口文件) ├── route/ # 路由定义 └── think # 命令行工具 `

public/ 目录是唯一对外暴露的目录,Web 服务器(Nginx/Apache)应将根目录指向这里,其他目录不应直接通过 URL 访问。config/ 目录下的配置文件按功能分类,如 database.phpcache.phpsession.php 等,可以通过 Config::get()config() 助手函数读取。

路由

ThinkPHP 6 的路由系统支持 RESTful 风格,可以定义各种 HTTP 方法的路由,以及资源路由、路由分组、路由中间件等高级功能。

`php // route/app.php use think\facade\Route;

Route::get('/', 'Index/index'); Route::get('user/:id', 'User/show'); Route::post('user/create', 'User/create');

// 资源路由(自动生成增删改查路由) Route::resource('article', 'Article'); `

Route::resource() 会自动生成 7 个标准 RESTful 路由:index(列表)、create(创建表单)、save(保存)、read(详情)、edit(编辑表单)、update(更新)、delete(删除)。路由可以添加参数验证、路由别名、路由缓存等,生产环境开启路由缓存可以显著提升路由解析速度。

控制器

控制器负责接收请求、调用模型处理业务逻辑、返回响应。ThinkPHP 6 的控制器是普通的 PHP 类,通过依赖注入获取 Request 对象。

`php // app/controller/User.php namespace app\controller;

use think\Request; use app\model\User as UserModel;

class User { public function index(): string { $users = UserModel::select(); return json($users); }

public function show(int $id): string { $user = UserModel::find($id); if (!$user) { return json(['error' => '用户不存在'], 404); } return json($user); }

public function create(Request $request): string { $data = $request->post(); $user = UserModel::create($data); return json($user); } } `

ThinkPHP 提供了丰富的助手函数:json() 返回 JSON 响应,view() 返回视图响应,redirect() 返回重定向响应。控制器方法的参数可以直接声明路由参数类型,框架会自动注入,例如 show(int $id) 会自动将路由中的 :id 转换为整数。

模型

ThinkPHP 的模型基于 Active Record 模式,每个模型对应一张数据表,提供了丰富的查询构造器方法,让数据库操作变得简洁直观。

`php // app/model/User.php namespace app\model;

use think\Model;

class User extends Model { protected $table = 'users';

// 自动时间戳 protected $autoWriteTimestamp = true;

// 字段类型 protected $type = [ 'status' => 'integer', ];

// 关联:一个用户有多篇文章 public function articles() { return $this->hasMany(Article::class); } }

// 使用 $users = User::where('status', 1)->order('id', 'desc')->limit(10)->select(); $user = User::find(1); $user = User::where('email', 'test@example.com')->find();

User::create(['name' => '张三', 'email' => 'zs@example.com']); User::where('id', 1)->update(['name' => '李四']); User::destroy(1); `

autoWriteTimestamp 开启后,模型会自动维护 create_timeupdate_time 字段,无需手动设置。模型的关联方法(hasManybelongsTohasOne 等)支持预加载(with()),可以有效避免 N+1 查询问题。

视图

ThinkPHP 内置了 Think 模板引擎,语法简洁,支持模板继承、变量输出、循环、条件判断等常用功能。

`php // 控制器中返回视图 public function index(): \think\response\View { $users = User::select(); return view('user/index', ['users' => $users]); } `

`html <!-- app/view/user/index.html --> {extend name="layout/base" /} {block name="content"} <ul> {volist name="users" id="user"} <li>{$user.name} - {$user.email}</li> {/volist} </ul> {/block} `

模板中的变量输出 {$var} 默认会进行 HTML 转义,防止 XSS 攻击。如果需要输出原始 HTML,使用 {$var|raw}。模板继承通过 {extend}{block} 实现,可以定义统一的布局模板,各页面只需填充内容区域。

数据库查询

除了模型,ThinkPHP 还提供了 Db 门面,可以直接执行 SQL 或使用查询构造器,适合复杂查询场景。

`php use think\facade\Db;

// 原生查询 $users = Db::query('SELECT * FROM users WHERE status = ?', [1]);

// 查询构造器 $users = Db::table('users') ->where('status', 1) ->where('age', '>', 18) ->order('created_at', 'desc') ->paginate(10);

// 事务 Db::transaction(function() { Db::table('accounts')->where('id', 1)->dec('balance', 100); Db::table('accounts')->where('id', 2)->inc('balance', 100); }); `

paginate() 方法会自动读取 $_GET['page'] 参数,返回分页对象,包含数据列表和分页信息。在视图中可以直接调用 $paginate->render() 输出分页 HTML。Db::transaction() 接受一个闭包,闭包内的所有操作在同一事务中执行,抛出异常时自动回滚。

中间件

中间件是处理 HTTP 请求的过滤层,可以在请求到达控制器之前或响应返回客户端之前执行逻辑,常用于身份验证、日志记录、跨域处理等。

`php // app/middleware/Auth.php namespace app\middleware;

class Auth { public function handle($request, \Closure $next) { if (!session('user_id')) { return redirect('/login'); } return $next($request); } }

// 在路由上使用 Route::get('dashboard', 'Dashboard/index')->middleware(\app\middleware\Auth::class); `

中间件可以在路由级别、控制器级别或全局级别注册。全局中间件在 app/middleware.php 中配置,对所有请求生效;路由中间件只对特定路由生效。中间件的 handle() 方法接收请求对象和下一个处理器,调用 $next($request) 将请求传递给下一个中间件或控制器。

验证器

ThinkPHP 内置了强大的验证器,可以集中定义验证规则,让控制器代码更加简洁。

`php // app/validate/User.php namespace app\validate;

use think\Validate;

class User extends Validate { protected $rule = [ 'username' => 'require|length:3,20|alphaDash', 'email' => 'require|email', 'password' => 'require|min:6', ];

protected $message = [ 'username.require' => '用户名不能为空', 'username.length' => '用户名长度为3-20个字符', 'email.email' => '邮箱格式不正确', ]; }

// 在控制器中使用 $validate = new \app\validate\User(); if (!$validate->check($data)) { return json(['error' => $validate->getError()], 422); }

验证器支持场景(Scene)功能,可以为不同操作(创建、更新)定义不同的验证规则,避免重复定义。内置了几十种验证规则,如 requireemailurlintegerbetweenunique 等,也支持自定义验证规则。

常见问题

Q1:ThinkPHP 6 和 Laravel 有什么区别,应该如何选择?

A:ThinkPHP 的优势是中文文档完善、国内社区活跃、上手快,适合国内中小型项目和快速开发;Laravel 的优势是国际社区庞大、生态丰富(Composer 包多)、设计更现代(依赖注入容器、契约接口),适合大型项目和需要与国际接轨的团队。如果团队以国内开发者为主、项目周期短,选 ThinkPHP;如果追求代码质量、需要丰富的第三方集成,选 Laravel。

Q2:ThinkPHP 的模型查询如何避免 N+1 问题?

A:N+1 问题是指查询列表时,对每条记录再单独查询关联数据,导致 N+1 次数据库查询。ThinkPHP 通过预加载(Eager Loading)解决:User::with('articles')->select() 会用两次查询获取所有用户及其文章,而不是 N+1 次。对于深层关联,可以用点语法:User::with('articles.comments')->select()

Q3:ThinkPHP 如何处理跨域请求(CORS)?

A:可以创建一个全局中间件处理 CORS 响应头:在 handle() 方法中调用 $next($request) 获取响应,然后给响应添加 Access-Control-Allow-OriginAccess-Control-Allow-Methods 等头部。也可以使用 topthink/think-cors 扩展包,通过配置文件灵活控制跨域策略。

Q4:ThinkPHP 项目如何部署到生产环境?

A:部署步骤:① 将代码上传到服务器,Web 根目录指向 public/;② 运行 composer install --no-dev 安装生产依赖;③ 修改 .env 文件,设置 APP_DEBUG=false、正确的数据库配置;④ 运行 php think optimize:all 生成路由缓存、配置缓存等优化文件;⑤ 确保 runtime/ 目录可写(日志、缓存存放位置);⑥ 配置 Nginx 的 try_files 指令,将所有请求转发到 index.php`。