PHP ThinkPHP 框架入门
ThinkPHP 是国内最流行的 PHP 框架,文档完善、中文友好,适合快速开发。ThinkPHP 6 基于 PHP 7.2+,采用单应用和多应用模式,内置了路由、ORM、模板引擎、缓存、队列等完整的 Web 开发组件。对于国内开发者来说,ThinkPHP 的中文文档和活跃的社区是其最大优势。
安装
ThinkPHP 通过 Composer 安装,think 命令行工具提供了代码生成、服务器启动等便捷功能。
# 需要先安装 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.php、cache.php、session.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_time 和 update_time 字段,无需手动设置。模型的关联方法(hasMany、belongsTo、hasOne 等)支持预加载(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)功能,可以为不同操作(创建、更新)定义不同的验证规则,避免重复定义。内置了几十种验证规则,如 require、email、url、integer、between、unique 等,也支持自定义验证规则。
常见问题
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-Origin、Access-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`。