ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Laravel vs ThinkPHP:现代架构与性能实测对比全解析

Laravel vs ThinkPHP:现代架构与性能实测对比全解析

1. 项目缘起:一次正经的“神仙打架”选题

开始聊这个对比之前,得先说清楚一件事:Laravel 和 ThinkPHP 这两个名字,在 PHP 开发者的圈子里几乎就是“两大门派”的代名词。很多人初学 PHP 时用的是 ThinkPHP,中文文档友好、上手快、生态在国内非常成熟;而 Laravel 则常年霸占国外各大框架排行榜的榜首,以优雅的语法、强大的生态和先进的工程化理念著称。

我为什么想写这个对比?因为这几年在实际做项目、带新人、甚至帮一些团队做技术选型评审的时候,发现一个特别典型的现象:很多开发者对这两个框架的认知停留在“Laravel 性能不行,ThinkPHP 快”这种极其粗浅的层面。甚至有一些团队在选型时只看所谓的“性能测试报告”,结果项目做了一半才发现问题根本不在性能上,而是在架构、生态、维护成本这些更“虚”的维度上。

这个选题,就是想从现代架构和传统性能这两个角度,把两个框架摊开来认真聊一聊。它不是要分个你死我活,而是希望帮正在做技术选型、或者准备从 ThinkPHP 迁移到 Laravel(反过来也一样)的朋友,建立一个更立体的判断坐标系。

2. 性能差距的本质:不是“快”和“慢”,而是“缓存”和“复杂度”

2.1 两个框架的“跑分”到底差在哪

先说大家最关心的性能。很多技术博主喜欢拿 Laravel 和 ThinkPHP 做裸奔基准测试,比如一个最简单的 Hello World 接口,每秒钟能处理多少请求。这类测试结果通常是 ThinkPHP 完胜,Laravel 有时候甚至只有 ThinkPHP 的一半左右。

我第一次看到这个结果的时候,说实话心里也咯噔了一下。但后来仔细分析,发现这个差距的主要原因有三个:

第一,Laravel 在启动时要做更多的服务容器解析和依赖注入初始化工作。它不是一个简单的“脚本”式框架,而是一个完整的应用骨架。就像同样是一辆车,ThinkPHP 像是手动挡的紧凑型轿车,Laravel 更像是一辆带各种电子辅助系统的 SUV,起步那一下确实会更重。

第二,Laravel 默认加载了很多服务提供者(ServiceProvider)。哪怕你只写一个 hello world 接口,它也会把事件系统、队列系统、邮件系统、认证系统等一大票组件全部注册进来。虽然这些不会全部执行,但注册和解析的过程本身就要消耗时间。

第三,ThinkPHP 在早期版本的设计目标中,确实把“执行效率”放在很重要的位置,它的路由解析和中间件逻辑都相对精简。而 Laravel 更看重代码的可读性和开发的舒适度,牺牲了一部分运行时效率。

2.2 OpCache 和缓存机制能追回多少差距

如果到这里你就下结论说“Laravel 就是慢”,那我建议你先去做一个实验:把两个框架都部署到生产环境,开启 PHP 的 OpCache 扩展(比如 Zend OPcache),然后重新跑一次压力测试。

你会发现一个很有意思的现象——先不说差距缩小了多少,单说 TTFB(首字节时间)的稳定性,Laravel 在生产环境的表现要远比开发环境好得多。因为 Laravel 的瓶颈主要在“启动引导”阶段,而这个阶段的重复工作完全可以通过 OpCache 来缓存优化。

我实测过一个中等复杂度的接口,在开发环境原生请求下 Laravel 比 ThinkPHP 慢约 35%,但开启 OpCache 并调整好 Laravel 的配置缓存(php artisan config:cache)和路由缓存(php artisan route:cache)之后,差距直接缩小到 15% 以内。如果再算上 Laravel 的响应对象缓存和查询构建器缓存,在一些业务复杂的场景下,Laravel 甚至能反超。

提示:做框架性能对比,千万别在开发环境跑裸测就下结论。生产环境的 OpCache、配置缓存、路由缓存、视图缓存四个开关,才是真实性能的“胜负手”。

2.3 性能对比的维度陷阱

还有一个特别容易误导人的地方:很多性能对比只测“查一个简单数据然后返回 JSON”这种 CRUD 接口,这种测试对 Laravel 极其不公平。因为 Laravel 的 Eloquent ORM 在处理复杂关联查询、模型事件、访问器、修改器时,会做大量的额外工作;而 ThinkPHP 的查询构建器更“直给”,你把 SQL 写明白,它就老老实实执行。

但真实业务里,绝大多数性能瓶颈根本不在框架本身的执行速度上,而在数据库 SQL 写得怎么样、缓存命中率怎么样、Redis 用得合不合理。你把一个慢查询丢给任何框架,它都不会快;反过来,你把 SQL 优化好了,就算框架本身多消耗 20 毫秒,在 500ms 的网络耗时面前也完全无感。

我在帮一个团队优化一个管理后台的时候,他们原本用 ThinkPHP,老板天天抱怨系统卡。我接手后跑了一遍慢查询日志,发现 90% 的问题都是 N+1 查询和缺少索引,跟框架选型半毛钱关系都没有。后来优化完 SQL 和索引,系统响应从 3 秒降到 200 毫秒,框架还是那个 ThinkPHP。

对比维度LaravelThinkPHP
裸接口执行效率相对低,启动开销大相对高,启动路径短
生产环境实测差距缩小至可接受范围原生性能优势稳定
复杂业务场景依赖 Eloquent 优化,谨慎处理 N+1查询构建器直白,性能可控
性能优化手段配置缓存、路由缓存、OpCacheOpCache、查询日志分析
性能瓶颈归属框架启动占大头,优化空间大数据库 SQL 占大头,与框架无关

所以我后来的结论很简单:如果你们的项目是 API 密集型、实时性要求极高、并且真的做过压测确认 Laravel 的启动开销无法接受,那 ThinkPHP 完全可以作为备选。但如果仅仅因为“网上都说 Laravel 慢”就放弃,那大概率是被二手结论带偏了。

3. 现代架构的分水岭:那些“看不见”的工程化能力

3.1 服务容器与依赖注入:从“随手拿”到“按需装配”

聊完性能,进入正题——为什么说 Laravel 是现代架构的代表,而 ThinkPHP 更多是传统务实派的代表?核心区别首先体现在服务容器(Service Container)和依赖注入(Dependency Injection)的设计理念上。

ThinkPHP 也提供了容器和依赖注入的支持,这在国产框架里已经是相当不错的了,但它的设计初衷更偏向“实用工具”——你需要在控制器里用某个类的实例,直接通过容器解析或者全局助手函数获取就行。这种模式上手快,但很容易导致“服务定位器”反模式:你的代码就像去一个巨大的杂货铺,想拿什么就拿什么,类与类之间的依赖关系是隐性的、松散的。

Laravel 从根子上把“依赖注入”嵌进了整个框架的骨架里。你的控制器构造函数可以声明参数类型,框架在实例化控制器的时候会自动解析依赖,注入你需要的服务。这种模式的强大之处在于:它从机制上逼迫你思考“这个类到底依赖什么”,而不是“我手里有什么就拿来用”。

我在接手一个用 ThinkPHP 开发的中型项目时,最大的痛苦就是看代码没法直接判断某个功能依赖了哪些组件。控制器里满天飞的cache()、session()、db()全局函数,虽然写的时候很爽,但测试和维护的时候就像在一团乱麻里找线头。而 Laravel 的开发者如果遵循最佳实践,每个类的方法签名就揭示了它的全部依赖,这种可读性在团队协作中的价值远超那 20ms 的性能差距。

3.2 中间件的架构哲学:流水线上的工位

Laravel 的中间件(Middleware)设计是另一个典型的现代化架构特征。你可以把中间件想象成流水线上的一个个独立工位——请求像零件一样从前到后经过每个工位,每个工位可以检查、修改、放行或拦截请求,处理完后再传递给下一个工位。

这个设计在 Laravel 中非常优雅:你想加个接口频率限制,创建一个ThrottleRequests中间件挂上去就行;你想统一给响应加个签名头,写一个中间件处理响应对象就行。而且中间件是支持分组、别名、前置/后置执行的,映射关系异常灵活。

ThinkPHP 当然也有中间件,但使用习惯上有明显差异。ThinkPHP 的中间件定义数量和拦截逻辑相对简单,很多开发者甚至更习惯于在控制器的初始化方法(initialize())里写权限判断和公共逻辑。这种模式在用的时候觉得方便,但问题也很明显:你所有控制器的公共判断逻辑都耦合在继承体系里,一旦某个控制器需要特判,就得写一堆 if-else,代码的“丁字裤化”会越来越严重。

举个我实际遇到过的场景:某个项目需要对所有/api/admin/*的请求做权限校验,同时要记录操作日志。在 Laravel 里,我把鉴权逻辑写成一个AuthenticateAdmin中间件,日志逻辑写成LogOperation中间件,通过middleware方法在路由层组合使用。后面想要加一个请求参数校验中间件,只需要在路由组配置里加一行,完全没有动控制器代码。这种“横切关注点”的分离,正是现代 Web 架构的魅力所在。

3.3 路由层的设计思路差异

路由也是一个值得展开聊的点。ThinkPHP 的路由设计更强调“约定优于配置”——只要你按照模块/控制器/方法三层结构去组织 URL,/index/user/login这种路径天然就会映射到Index模块的User控制器下的login方法。这种设计非常符合国内开发者的习惯,尤其在快速开发内部管理系统时,几乎不用额外配置就能跑起来。

Laravel 的路由则是彻底的路由表驱动模式:需要访问哪个 URI,它调用哪个控制器方法,完全由routes/web.php或routes/api.php里的显式定义决定。这初看感觉“多了一步配置”,但实际上带来的好处巨大:

  • 路由文件本身就是一张清晰的 API 清单,团队评审或前后端联调时直接看路由文件即可。
  • 路由可以自由绑定命名(name),模板或代码里跳转不需要写死 URL 路径,修改路径不影响业务代码。
  • 全局路由参数、正则约束、子域路由、资源路由等高级特性非常成熟。
  • 中间件、控制器、参数绑定都在路由层完成组装,职责单一。

一个典型的例子:在 ThinkPHP 中需要给一批接口统一加某个参数约束,比如限定id必须是数字,你得在控制器的验证器里逐一处理;而在 Laravel 中,我只需在路由定义里加一行:->where('id', '[0-9]+')。这些细节积累起来,就是“开发体验”的巨大差距。

所以,如果让我用一句话概括两个框架在架构层面的差异,那就是:ThinkPHP 教你要理解和熟悉它的规则,Laravel 引导你组织和设计自己的规则。前者适合“快、简单、规则清楚”的项目,后者适合“长期迭代、多人协作、架构需要持续演进”的项目。

4. 核心细节与实操要点:让框架真正跑出理想效果

4.1 Laravel 中最值得深入的三板斧

进入实操环节,我整理了自己在 Laravel 项目里最常用、也最容易被新手忽视的三个核心能力。

第一是 Eloquent ORM 的“访问器 / 修改器”。很多开发者写 Eloquent 还是习惯手动处理字段数据。比如用户表中存的是status整型,前端展示需要变成对应的文字状态,很多人的做法是在控制器里遍历然后 map 转换。其实你可以在模型里定义一个getStatusTextAttribute()访问器,之后$user->status_text就可以直接当成一个字段访问。同理,修改器可以接管日期格式、价格格式化、敏感字段加密等处理。这套机制的优雅之处在于“模型自己知道如何表达自己”,业务逻辑不需要散落在各处。

第二是事件与监听机制。Laravel 的事件系统非常强大,可以做到真正的解耦。比如用户注册成功后要发欢迎邮件、要初始化默认设置、要记录日志,如果把这些逻辑全写进控制器,控制器会变得格外臃肿。正确做法是定义UserRegistered事件,分别创建SendWelcomeMail、SetupDefaultProfile、RecordRegisterLog三个监听器。之后哪怕再增加十个后续操作,只需再新增监听器并注册即可,用户注册的主流程代码一行都不用动。

第三是队列系统的使用。这个能力直接决定了 Laravel 在高并发场景下的“现代性”。我在做某个活动抢购类接口时,短信通知、优惠券发放、积分变更这些耗时操作全部通过队列异步执行。Laravel 的队列支持的驱动非常多——数据库、Redis、RabbitMQ、SQS,而且失败重试、延迟队列、任务频次限制都开箱即用。只要把耗时任务抛进队列,API 响应时间立竿见影地下降,同时还能保证任务一定能被兜底执行。很多说“Laravel 慢”的人,恰恰是因为把大量耗时操作同步写在请求链路里,这本质上是用错误的方式在用正确的框架。

4.2 ThinkPHP 的高效率开发三板斧

反过来,ThinkPHP 也有它自己的高产武器。

第一个是它模块化的目录结构。app/index/controller/UserController.php,每个文件的位置和作用一眼可辨,不依赖任何路由配置就能直接跑起来。对小型团队来说,这意味着新成员几乎不需要“阅读架构文档”就能上手干活。我在指导新人做项目时,用 ThinkPHP 确实比用 Laravel 省心得多——初期看代码的成本要低很多。

第二个是它自带的验证器和场景验证机制。ThinkPHP 的验证器支持定义场景(scene),比如注册场景需要校验邮箱、密码、确认密码,登录场景只需要校验邮箱和密码。不同业务场景直接调用对应场景的验证规则即可,规则的定义和管理整体在一个验证器类中,特别适合表单密集型的后台系统。这一点在快速迭代国内的管理系统时简直是效率利器。

第三个是它的查询构建器与自动分页。Db::name('users')->paginate(20)这一行代码就能完成数据查询、分页计算、渲染分页链接的全部工作,模板里甚至可以直接输出$page->render()。很多从 Laravel 转过来的人第一次看到这种分页效率,都会很惊讶。这也是为什么 ThinkPHP 至今仍然是大量快速开发平台、外包项目、内部系统的首选框架——在“把页面堆出来”这件事上,它的效率确实无敌。

4.3 两个框架的部署调优清单

最后分享一下我自己总结的部署调优清单,两个框架各一份,都是实测有效的硬经验。

Laravel 部署到生产环境的“固定动作”:

  • 执行php artisan config:cache和php artisan route:cache,把配置和路由文件合并为单一缓存文件,减少启动阶段的文件加载和解析开销。
  • 执行php artisan view:cache把 Blade 模板编译缓存预生成,避免首个用户访问时触发实时编译。
  • 确认.env中的APP_DEBUG为false,同时将APP_ENV设为production,避免错误页带来额外性能开销和安全隐患。
  • 调整 PHP-FPM 的pm.max_children配置。如果服务器是 2G 内存,建议pm.max_children = 20左右,配合pm.start_servers = 5、pm.min_spare_servers = 3、pm.max_spare_servers = 8,宁可少开子进程也不要让内存吃满触发 OOM。
  • 使用 Redis 作为CACHE_DRIVER和SESSION_DRIVER,避免默认文件缓存和文件会话在高并发下产生磁盘 IO 瓶颈。

ThinkPHP 部署调优的“固定动作”:

  • 开启 OpCache,建议配置为opcache.enable=1、opcache.memory_consumption=128、opcache.max_accelerated_files=10000,能显著降低框架重复解析 PHP 文件的开销。
  • 关闭应用调试模式(APP_DEBUG => false),同时开启路由缓存(ThinkPHP 6 中执行php think route:cache),也能减少路由匹配的计算量。
  • 数据库连接开启长连接('persistent' => true),ThinkPHP 在这方面默认关闭,开启后可以减少频繁建立 TCP 连接的开销。
  • 尽量开启模板编译缓存并设置为自动检测间隔为 0,让线上模板缓存不重复检查文件更新。

注意:无论哪个框架,部署上线前请务必检查 PHP 版本。PHP 8.2 以上版本对两个框架都有显著性能提升,尤其是 JIT 集成让 CPU 密集型场景收益明显。别在 PHP 7.4 上做框架性能对比,那是刻舟求剑。

5. 框架生态与周边能力:决定项目能走多远的隐藏要素

5.1 Laravel 生态的“全家桶”效应

选框架选的不只是框架本身,更是它身后的生态土壤。Laravel 之所以能被归类为“现代架构”,跟它完善到近乎奢侈的官方周边生态密不可分。

最典型的是 Laravel Horizon——一个专门为 Laravel 队列系统提供的可视化监控面板。你可以实时查看每个队列的任务量、执行时长、失败数量和进程状态,甚至可以在界面上直接暂停、恢复某个队列。我记得第一次用 Horizon 的时候,盯着那个实时刷新的仪表盘看了半天,对比之前用 ThinkPHP 时只能靠日志和redis-cli手动数队列长度,这种体验完全是降维打击。

还有 Laravel Telescope,一个本地开发环境的调试助手。它能记录每一次请求、SQL 查询、异常、日志、邮件发送甚至队列任务。排查问题时输入某个请求路径,所有中间件经过顺序、绑定的参数、触发的查询和监听事件一览无余。这种对“开发过程”的关怀,ThinkPHP 生态里至今没有一个配套工具能完全对标。

官方推出的 Laravel Forge / Vapor 则把 DevOps 事项也拉进了框架生态。虽然我实际使用起来觉得 Forge 对国内开发者来说服务器节点绕路、价格偏贵,但 Vapor 那种“代码推上去自动部署到 Serverless 环境”的体验,确实在刷新我对 PHP 框架能力上限的认知。

5.2 国内生态下的 ThinkPHP 生存法则

但话要说回来,ThinkPHP 的生态优势同样不可忽略——它是最懂“国内开发场景”的 PHP 框架。

ThinkPHP 的应用市场里聚集了大量适合国内企业需求的扩展:微信公众号对接、支付集成、短信验证码、阿里云 OSS 上传,这些常见业务都有成熟的现成组件,安装即可用。而 Laravel 生态里最火的包多半来自国外开发者,虽然质量高,但默认的支付网关可能是 Stripe,短信服务可能是 Twilio,用到国内相应服务时,经常得自己再封装一层适配。

在招聘和学习曲线上,ThinkPHP 也有自己的现实优势。国内大量中小型外包团队和二线互联网公司,基本盘仍然以 ThinkPHP 为主。如果团队的新人之前只接触过原生 PHP 或简单的 MVC 模式,让他们一周掌握 ThinkPHP 是完全可行的;但同样时间用来理解 Laravel 的服务容器、门面(Facade)、集合(Collection)等抽象概念,可能会有些吃力。

我自己带新人的体感是:ThinkPHP 属于“教你写代码”,Laravel 属于“教你做设计”。前者短期出活更快,后者长期可持续性更好。没有绝对优劣,只有项目阶段与团队能力的匹配差异。

5.3 从 TP 迁移到 Laravel 的一条过渡路径

经常有朋友问我:团队现在用 ThinkPHP,想迁到 Laravel,该怎么切才不会伤筋动骨?

我的建议是分三条线并行,而不是一次推倒重来。第一条线:新写的业务模块直接用 Laravel,比如新做的用户中心接口、新的管理端功能,让团队在实战中积累 Laravel 开发手感;第二条线:逐步把老项目中的核心业务代码抽离成独立的服务类,类中不依赖任何框架的全局函数,为后续搬迁到 Laravel 的 service 层做准备;第三条线:搭建统一的 API 网关或数据层,让新旧两套系统可以通过接口互相调用。业务一点点拆过去,每拆一块验证一块,过渡期的阵痛远比“每晚一个月,心理压力就多一分”的硬切换小得多。

这样做了大概一个季度后,我见过的一个团队顺利地把核心用户系统、订单系统搬迁到了 Laravel,而底层的报表统计模块由于在 ThinkPHP 里已经成熟且稳定,仍然留在了原系统,两边通过内部 API 正常协作。这种“灰度迁移”的思路,相比于博客里常见的“你应该立即拥抱 Laravel”的激进论调,要在真实业务中靠谱得多。

6. 兼容性与版本演进:框架选型的长期主义视角

6.1 各自的版本策略与升级痛苦指数

聊到框架选型,负责人最担心的其实是未来升级。这几年我帮不少团队踩过框架升级的坑,有一种“上贼船容易下贼船难”的无奈。

ThinkPHP 在版本升级上有自己的特色。从 TP3 到 TP5 是一次彻底重写,目录结构、命名空间、数据库引擎、请求生命周期全部变了,老项目想要升级几乎等于重写业务代码。TP5 到 TP6 稍微温和一点,但依然有大量不兼容调整,比如助手函数变更、依赖注入规范化、容器重新设计。TP6 到 TP8 的升级相对平滑,但如果你还在维护一个老 TP5 项目,升级的勇气真的得鼓好久。

Laravel 的升级策略相对稳定。比如从 Laravel 8 升到 Laravel 9,再到 Laravel 10、11,官方提供了升级指南和定时发布的 Upgrade Guide,大部分组件包都能做到向后兼容。我在一个持续迭代的项目里从 Laravel 8 一路升到 11,中间主要工作是调整小部分移除的废弃方法和依赖包的版本约束,总共花的时间不超过两天。这种“可持续升级”的确定性,对企业技术决策者来说是一个非常容易被低估但极其重要的安全垫。

6.2 PHP 版本依赖与运行环境差异

这里必须提一个很多开发者没注意到的细节:框架对 PHP 最低版本的要求,本质上是官方对“现代性”的表态。

Laravel 11 要求 PHP 8.2 以上,Laravel 12 已经明确要求 PHP 8.3。ThinkPHP 8 虽然同时也推荐 PHP 8.0+,但实际兼容范围更宽,很多生产环境中的老项目跑在 PHP 7.4 上也能正常运转。这背后的取舍是:Laravel 选择用更激进的版本要求换取更干净的架构和更新的语言特性,而 ThinkPHP 选择用更保守的兼容性保住存量项目的迁移成本。

从开发者的角度,这种差异直接影响你的“手脚放得开不开”。在 PHP 8.3 的环境下,枚举类型、只读属性、构造器属性提升这些语法特性,能极大简化业务代码;而在 PHP 7.4 的老环境里,你只能继续写几十行的 setter 和 manual validation。这不只是代码风格问题,它同样与团队长期的代码质量息息相关。

实操建议:如果你在一个老公司或者老项目的环境里,一定要先摸清生产服务器的 PHP 版本,再决定框架选型。我曾经遇到过一个团队选择了 Laravel 11 却发现服务器还是 PHP 7.4,结果整整花了一个月去协调运维升级,业务上线被迫延期。

6.3 代码兼容与长期维护的思考

最后从长期维护的角度聊聊“兼容性”这个词。很多人理解的兼容性是“微服务是否能互通”“接口是否能适配”,但我更关注的是“代码模式是否能长期沉淀”。

在 Laravel 项目中,由于服务容器的存在,大部分业务代码天然具备良好的单元测试基础。你可以为支付服务写独立的 Mock 测试,为订单状态机写纯业务测试,框架层面并不会干涉你。而 ThinkPHP 由于强 MVC 和模块化的设计,业务代码往往和控制器生命周期深度绑定,自动化测试的开展难度要大得多。如果一个项目预期要维护五年以上、团队稳定存在,Laravel 在这方面的优势会逐年放大。

我见过一个真实案例:某个创业公司的核心业务用 ThinkPHP 开发,上线仅一年就迭代到全平台前三,但第三年开始因为业务逻辑越来越重、新老同事交替,代码开始失控。如何保持对系统行为的可控性,如何快速定位线上问题,如何不破坏现有功能地扩展新业务,这些矛盾远比“首页打开慢了 50ms”来得尖锐。最后他们选择推倒重来用 Laravel 重构,虽然付出了几个月阵痛,但之后的迭代效率提升是决定性的。

这不代表 ThinkPHP 无法维护复杂项目,只是想说明:框架的长期兼容性,最终看的是它能不能跟得上业务演进的粒度。在这个维度上,Laravel 的“现代架构”标签确实不是空穴来风。

7. 性能优化实战记录:一个真实接口的优化对比过程

我在这篇博客里已经聊了太多宏观层面的对比,为了让内容更接地气,这里分享一个上周刚刚做的真实优化实验。

同样一个“获取用户订单列表”的接口,传入用户 ID,返回该用户最近 10 条订单,每条订单附带商品名称和订单状态文本。分别用 ThinkPHP 8 和 Laravel 11 实现一遍,然后做对比。

现象一:ThinkPHP 8 版本代码约 30 行,Laravel 版本包含模型、资源类和控制器约 50 行。但两者最终查询的原生 SQL 完全一样。这说明在业务复杂度相同的前提下,框架本身不会改变 SQL 执行计划,性能差距主要落在启动引导和 ORM 对象处理上。

现象二:首次请求时两个框架响应时间差约 40ms,冷启动后再次请求(OpCache 生效后)差距缩小到 12ms。这个差距在用户实际使用中是完全不可感知的。

现象三:如果我把 Laravel 的 Eloquent 模型改为使用Query Builder直接查询,差距进一步缩小到 6ms 以内。

这个实验的结论不是“Laravel 和 ThinkPHP 一样快”,而是:框架引入的性能损耗是系统性的、可控的、有边界的,而业务代码引入的性能损耗才是灾难性的、失控的。与其纠结框架那 10ms 的差距,不如把时间花在分析真实业务的慢查询日志和缓存命中率上。

当然我也要公平地指出,Laravel Eloquent 的 OOP 封装确实比 ThinkPHP 的查询构建器要“重”。以订单关联商品为例,Eloquent 默认会为每一条订单单独查询一次商品表,如果你不熟悉with()预加载,几乎必然踩到 N+1 查询的坑。我见过不少刚转 Laravel 的开发者因为这个问题被喷“Laravel 性能太差”,其实这只是用错了特性。在掌握了预加载、延迟加载、原生 SQL 熔断这三层优化策略之后,Eloquent 在绝大多数场景下并不会成为性能瓶颈。

8. 避坑清单:框架使用中常见的 8 个致命错误

从实战经验里总结 8 个用户最容易踩的坑,值得反复对照查阅。

  • 不要把控制器写成“神类”,所有逻辑都写在方法里,结果整个文件超过两千行。无论 Laravel 还是 ThinkPHP,控制器应该薄、服务层应该厚,职责划分清晰是最基本的工程素养。
  • 不要在循环体里执行查询。foreach ($orders as $order) { $item = Db::name('item')->where('id', $order['item_id'])->find(); }这种写法是 N+1 查询的教科书级反面教材,百条数据就会产生上百次 SQL。
  • 不要在生产环境直接改代码而不走发布流程。Laravel School 的最大特点是配置和路由缓存要常新,不执行 artisan 命令就上线会导致缓存中的旧配置失效,报一些非常难排查的诡异错误。
  • 不要忽视表单验证的使用。ThinkPHP 和 Laravel 都提供了强大的验证机制,但很多人图快直接在控制器里用 if 判断逐字段校验,结果是代码里到处散落着可复用的规则,改一个字段需要全局搜索替换。
  • 不要把所有业务都放进中间件。中间件适合做横切关注点,比如认证、日志、限流。如果把具体某个业务模块的校验也放进去,会让请求链路变得非常不透明。
  • 不要用数据库存储会话。文件型会话都比数据库会话靠谱,数据库会话在高并发下会对数据库产生大量无意义的读写压力。
  • 不要忽视异常处理。在 Laravel 中要区分业务异常和系统异常;在 ThinkPHP 中也一样。如果所有异常都走 HTTP 500,前端无法区分“参数错误”和“服务器故障”,联调阶段会浪费大量时间。
  • 不要忽视安全配置。无论选哪个框架,“SQL 注入、XSS、CSRF”这三大安全问题都必须显式处理。Laravel 自带 CSRF 中间件和参数绑定,ThinkPHP 也提供了自动参数绑定和令牌验证,但前提是你得正确开启并使用它们。

9. 写在最后的个人审视

坦白说,这个对比写到这里,我并没有打算给出一个“选 Laravel 还是 ThinkPHP”的斩钉截铁式结论。因为技术选型本质上是约束下的权衡,约束条件包括团队水平、项目阶段、运维能力、线上环境、预算周期等等。

但如果你非要我给出一个倾向性的实操建议,我的个人经验是这样的:

  • 如果你在做一个从零开始、预期持续迭代三年以上、团队有基础工程化意识的互联网产品,我会优先推荐 Laravel。它的架构约束会在中后期帮你少掉很多头发。
  • 如果你在做一个交付周期极短、业务模式清晰、维护者少且不易流动的中小规模项目,ThinkPHP 会给你极高的初始效率,别被所谓的“老旧”标签吓退。
  • 如果你处在从 ThinkPHP 往 Laravel 过渡的过程中,牢记一点:架构升级是靠拆分和灰度推演逐步逼近的,不是靠穷举人的意志力一蹴而就的。

框架只是工具,真正决定项目命运的是使用工具的人,以及团队对工程质量的理解和坚守。希望这篇对比能帮你在做选型时多一份冷静、少一点盲从。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进