各位同学,大家下午好!
我是你们的老朋友,那个在深夜里跟 Laravel 报错死磕,然后又在周末写 PHP 单元测试乐此不疲的“资深专家”。今天我们不讲 ORM,不讲队列,也不讲视图渲染的 HTML 结构。今天我们要聊的是点更本质的东西——“空”。
是的,空。
欢迎来到 Laravel 11 的重构现场。如果你们是用过 Laravel 8、9 甚至 10 的,你们大概会闻到一股熟悉的“味道”。那是一种什么味道呢?那是“你大爷”的味道。以前我们在搭建一个项目时,感觉就像是在装修一个别人已经装修好的豪宅,然后还要自己重新刷一遍墙。Laravel 11 就是要把这栋豪宅拆了,然后只给你留一个水泥地,让你自己想盖个鸡窝还是盖个城堡,随你便。
今天,我就要带大家深入剖析 Laravel 11 的“精简进化论”。我们要看看,这帮大牛到底是怎么把“脚手架”这个本来应该是帮忙的工具,硬生生变成了拖慢你进度的绊脚石的。现在,他们决定帮你把绊脚石搬走了。
第一讲:那个让你头秃的 config/app.php
让我们把时钟拨回到 Laravel 10(甚至更早)的时代。当你 composer create-project laravel/laravel my-app 的时候,你有没有过一种感觉:这配置文件怎么比我奶奶的针线筐还乱?
config/app.php,这是应用的灵魂入口配置。打开它,映入眼帘的是什么?locale(语言环境),fallback_locale(后备语言环境),key(加密密钥),providers(服务提供者列表),aliases(别名映射)。
在那个年代,如果你想改一下时区,你必须在文件里写 timezone => ‘Asia/Shanghai’。如果你想改一下加密密钥,你必须敲手写个随机的字符串,万一忘了,你就得查 GitHub。
这叫什么?这叫“配置地狱”。
更糟糕的是什么?默认情况下,Laravel 10 会帮你把这些东西填得满满当当,仿佛生怕你不知道怎么用。但你真的需要吗?对于大多数刚刚起步的 CRUD(增删改查)项目,你真的需要配置那么多东西吗?
Laravel 11 的变革:拥抱“默认值”。
Laravel 11 做了一件非常“叛逆”的事情。它大大精简了默认配置。如果你的项目不需要自定义语言包,不需要复杂的别名映射,Laravel 11 会直接把 config/app.php 变得极其干净。
你看下面这段对比,简直就是从“违章建筑”变成了“极简主义艺术”。
Laravel 10 的 config/app.php (浓缩版):
<?php
return [
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
*/
'name' => env('APP_NAME', 'Laravel'),
/*
|--------------------------------------------------------------------------
| Application Environment
|--------------------------------------------------------------------------
*/
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
*/
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
*/
'url' => env('APP_URL', 'http://localhost'),
// ... 后面还有一堆关于 timezone, locale, providers 的配置
];
Laravel 11 的 bootstrap/config.php (极度精简):
<?php
return [
'name' => env('APP_NAME', 'Laravel'),
'env' => env('APP_ENV', 'production'),
'debug' => (bool) env('APP_DEBUG', false),
'url' => env('APP_URL', 'http://localhost'),
'timezone' => 'UTC', // 默认就是 UTC,不折腾,别瞎改
'locale' => 'en', // 默认就是 en,你要是写中文项目,这个你迟早要改
'key' => env('APP_KEY'), // 这一个是最重要的,其他的都是可以猜的
];
专家点评:
这就好比你去买鞋。以前买鞋,销售员给你一双鞋,上面挂着一大堆说明书:“如何调节松紧带”、“如何清洗皮革”、“如何根据左脚脚掌调整鞋垫”。你只想走路,结果手里拿了一本《鞋类百科全书》。
Laravel 11 把那本百科全书抽走了。它给你一双“通用鞋”,穿上就能跑。除非你要跑马拉松(需要定制配置),否则别去碰那些设置。这直接降低了“心智负担”:你不需要在脑子里背诵那些配置项,你只需要知道 APP_KEY 是干嘛的。
第二讲:bootstrap/app.php 的“路由权”争夺战
在 Laravel 10 之前,如果你要定义路由,你得去 routes/web.php,然后你还得写一个 RouteServiceProvider。这听起来很合理对吧?面向对象,服务提供者管理服务,路由也是服务,对吧?
大错特错!
在 Laravel 10 甚至更早的版本里,RouteServiceProvider 是路由的“宿主”。你必须在 boot() 方法里写 $this->routes->web(function () { ... });。如果你有 API 路由,你还得写 $this->routes->api(...)。
这导致了什么?架构的臃肿。 你的项目启动流程变成了这样:
AppServiceProvider启动。AuthServiceProvider启动。EventServiceProvider启动。RouteServiceProvider启动,然后才轮到路由文件web.php跑起来。
这就像是你开车去上班,必须先去加油站加满油,再去洗车店把车洗一遍,再去修车店检查轮胎,最后才能坐进驾驶室。
Laravel 11 的变革:路由的独立与“闭包式”自由。
Laravel 11 彻底颠覆了这一点。它引入了 bootstrap/app.php。这是应用启动的核心,但现在,路由在这里注册,而不是在服务提供者里。
这是一个巨大的心智负担减负。
Laravel 10 的写法 (app/Providers/RouteServiceProvider.php):
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
use IlluminateRoutingRouter;
class RouteServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->routes(function (Router $router) {
$router->group(prefix: 'api', middleware: ['api', 'throttle:60,1'], namespace: 'App\Http\Controllers\Api', function: function () {
require base_path('routes/api.php');
});
$router->group(['middleware' => 'web'], function () {
require base_path('routes/web.php');
});
});
}
}
Laravel 11 的写法 (bootstrap/app.php):
<?php
use IlluminateFoundationApplication;
use IlluminateRoutingRoute as LaravelRoute;
use IlluminateSupportFacadesRoute;
use IlluminateSupportServiceProvider;
return Application::configure(basePath: dirname(__DIR__))
->withProviders(providers: [
// 这里注册全局 Providers
AppProvidersAppServiceProvider::class,
])
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->create();
专家点评:
看到了吗?以前你要写一个类,继承 ServiceProvider,写一个 boot 方法,然后在里面写 $this->routes(...)。Laravel 11 把这个步骤砍掉了。
你甚至不需要创建 RouteServiceProvider 文件!只要在 bootstrap/app.php 里加一行配置 withRouting,路由就挂上了。
这是什么?这就是“按需加载”的极致。你不需要一个“路由服务提供者”来“提供”路由,路由就是代码文件,就像 composer.json 一样,它在哪,它就是哪。
对于开发者来说,这意味着什么?意味着你少了一个要命的选择困难症:
“我该把这个路由放在哪个 Provider 的 boot 方法里?”
“这个路由需要中间件吗?我是不是得去修改 Provider 的配置?”
Laravel 11 的答案是:别想了,直接在 web.php 里写。 想用中间件?直接在 bootstrap/app.php 的 withMiddleware 里配置,或者直接在路由闭包里加。代码即配置,配置即代码。
第三讲:AppServiceProvider 的“自杀”事件
在 Laravel 10 中,当你运行 php artisan make:provider 时,你会得到一个默认的 AppServiceProvider。它看起来是这样的:
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}
请允许我大声发问:这玩意儿有啥用?
如果你是一个初级开发者,你可能会想:“哦,这里有 register 方法,那我写个服务容器绑定试试?”
如果你是一个中级开发者,你会想:“boot 方法里可以发布配置文件,或者是给模型加全局作用域。”
但事实是,绝大多数项目,这两块都是空的。你每次创建项目,都要把这个文件留在那吃灰,或者为了显得“专业”而填满它。这就造成了“环境噪音”。当你打开这个文件,看到一大堆空行和注释,你心里会犯嘀咕:“我该在这里放代码吗?还是删掉它?删掉它会不会破坏框架?”
Laravel 11 的变革:默认即为零。
Laravel 11 甚至在新建项目时,默认都不再提供这个空壳 Provider(虽然你可以手动加)。它鼓励你删掉它。
为什么?因为依赖注入容器(Service Container)和中间件是自动注入的,配置发布是自动的。你不需要一个专门的类来声明“我是启动类”。
这极大地提升了心智负担的清晰度。
以前你的项目结构里,可能有 3-5 个 Provider,每个都有 boot 方法。你在调试时,得考虑“我的这段代码是在哪个 Provider 的 boot 里执行的?”。
现在?没有了。代码就在路由里,就在控制器里,就在闭包里。上下文就在你眼前。
第四讲:php artisan serve 的“温柔陷阱”
让我们聊聊本地开发环境。Laravel 10 时代,你想在本地跑个项目,通常怎么做?
- 打开 XAMPP/WAMP/MAMP。
- 启动 Apache/Nginx。
- 配置虚拟主机(Vhost),指向你的项目文件夹。
- 访问
http://project-name.test。
这个过程繁琐吗?不繁琐,但是它占地方。它意味着你需要维护一个完整的服务器环境,甚至有时候 Apache 配置稍微搞错个 AllowOverride,你的路由就404了。
Laravel 11 的变革:自带 HTTP 服务器。
Laravel 11 的 php artisan serve 做了一个惊人的决定:默认监听 8080 端口,并且默认开启 HTTPS。
不需要 Apache,不需要 Nginx,甚至不需要配置 hosts 文件。只要你有 PHP,你就能跑。
代码示例:
$ php artisan serve
INFO Server running on [http://127.0.0.1:8080].
INFO Webserver started.
专家点评:
这就好比你以前盖房子需要自己砌墙、自己接水管、自己拉电线,现在 Laravel 11 直接给你送了一栋精装房,插上电就能住。
HTTPS 开启是什么概念?这意味着你的前端 JavaScript(比如 Axios)在本地开发时,不需要写一大堆 proxy 配置或者 CORS 跨域处理了!以前开发前后端分离,跨域问题能让你头秃,现在 localhost:8080 的请求默认就是安全的,这就是“零摩擦”开发体验。
第五讲:目录结构的“去层级化”与“文件夹到极致”
Laravel 一直以目录结构清晰著称,但这在某些情况下也成了负担。Laravel 10 要求你有明确的目录划分:Controllers, Models, Services, Repositories, Transformers。
有时候你会陷入文件夹命名焦虑:我到底该把业务逻辑放在 Services 还是 BusinessLogic?我到底该把 API 响应放在 Transformers 还是 Resources?
Laravel 11 的变革:宽容的目录结构。
Laravel 11 更加扁平化。它默认创建的目录非常少。它鼓励你把文件放在离它们要被调用最近的地方。
同时,Laravel 11 引入了一个新的命令:php artisan make:controller。默认情况下,它只会创建一个空的控制器文件。
$ php artisan make:controller PostController
Controller created successfully.
你看,没有 PostController.php,没有 PostControllerFactory.php,没有 PostControllerRequest.php(虽然那个是 Form Request,但默认也不生成)。它只给了你一个骨架。
这迫使你必须思考:“这个控制器是用来干嘛的?”。
以前,Laravel 10 会强迫你往这个文件里塞进一堆代码,因为你已经建好这个“坑”了,不填点东西觉得浪费。
现在,Laravel 11 把坑填平了,让你轻装上阵。
第六讲:核心变革——从“框架思维”到“代码思维”
好了,说了这么多关于配置、路由、目录的“减法”,我们终于要聊到最核心的部分了:心智负担。
什么是“心智负担”?
- 心智负担 A:我想写一个简单的登录功能。我需要写 SQL 吗?需要写逻辑吗?需要写前端吗?-> 这是业务负担。
- 心智负担 B:我该怎么把这个登录逻辑接入到 Laravel 的认证系统里?我该用哪个 Facade?我该在哪个中间件里写?我该把数据库配置放在
config/database.php的哪个数组里?-> 这是框架负担。
Laravel 11 的所有变革,本质上都是在做一件事:消灭 心智负担 B。
1. 闭包路由的回归与流行
在 Laravel 10,为了图个方便,大家喜欢用闭包写路由。
Route::get('/user/{id}', function (Request $request, $id) {
return User::findOrFail($id);
});
但是在复杂的业务里,闭包写多了代码会乱。于是大家开始把逻辑抽到 Controller。
Laravel 11 重新让闭包变得优雅。因为有了 bootstrap/app.php 的简化,闭包路由不再显得“不专业”。
use IlluminateSupportFacadesRoute;
// 在 bootstrap/app.php 的 withRouting 配置中,或者直接在这里
Route::get('/test', function () {
return 'Hello World';
});
你不需要 Controller,不需要 Class,甚至不需要命名空间。你想要个端点?写个闭包就完事了。这对于写脚本、写微服务、写 API 探针来说,简直是神器。
2. “注册”即“定义”
在 Laravel 10,我们要使用某个功能,比如队列或者广播,通常需要注册一个 QueueServiceProvider,然后在 config/queue.php 里配置 connections。
在 Laravel 11,bootstrap/app.php 里的 withQueue 配置非常直观。
->withQueue(
connections: [
'database' => [
'driver' => 'database',
'table' => 'jobs',
'retry_after' => 90,
],
]
)
它不再强迫你去理解“服务提供者”这个设计模式,只要懂配置数组就行。
3. 依赖注入的无感化
Laravel 一直号称“依赖注入框架”,但在实际开发中,特别是使用 Facade 时,很多开发者忘记了容器注入的存在。Laravel 11 通过精简服务容器,让依赖注入变得更“隐式”。
你不再需要到处去寻找 App::make() 或者 resolve(),因为 PHP 的构造函数和类型提示已经足够强大。
// 以前你可能需要在一个 Service Provider 里手写绑定
// public function register(): void
// {
// $this->app->singleton(UserRepository::class, EloquentUserRepository::class);
// }
// 现在,Laravel 11 默认的 Eloquent Model 就是你的 Repository
// 你直接在 Controller 里用,框架自动搞定,不需要你注册。
class UserController extends Controller
{
public function __construct(
private User $user // Type hinted constructor property promotion
) {}
public function show(int $id)
{
return $this->user->findOrFail($id);
}
}
你看,Laravel 11 鼓励使用构造函数属性提升。这行代码比以前的一大段 Provider 注册代码要清晰得多,也优雅得多。这直接降低了开发者理解“容器”的门槛。
第七讲:错误处理的“友好化”
在 Laravel 10,如果你访问一个不存在的路由,你会看到一屏黄色的堆栈跟踪。那是 1970 年代程序员留下的 DNA,虽然有用,但是吓人。
Laravel 11 改变了默认的错误视图。它更加现代、简洁,并且默认只显示“哎呀,出错了”,而不是“你在第 10 行第 5 列犯了个错”。
当然,你可以随时通过环境变量切换回详细模式,但默认的“友好模式”极大地降低了普通用户的恐慌感。
总结:为什么我们要拥抱“极简”?
各位,我写代码这么多年,见过最贵的代码不是 CPU 开销最高的代码,也不是内存溢出的代码,而是开发者最不想打开的代码。
当一个 Laravel 项目,app/Providers 下面躺着一堆空的、继承自 ServiceProvider 的僵尸类,config 目录下有几百行你根本读不懂的默认配置时,开发者的第一反应是:“天哪,又要修这个项目了,这配置太乱了。”
Laravel 11 的这次变革,是一次“反向工程”。它不是在增加新功能,而是在删除旧功能。它删除的是“臃肿”,删除的是“仪式感”,删除的是“你必须这么做”的强迫症。
它提升了心智负担吗?
没有。
它把从“如何理解框架机制”转移到“如何解决业务问题”上。它把 80% 的框架底层逻辑隐藏到了后台,只暴露给开发者那 20% 最核心的配置。
它就像是你手里的一把瑞士军刀。
Laravel 10 以前的版本,那把刀是个大家伙,前面有锯子,后面有开瓶器,侧面有起钉器。你要用刀切苹果,你得先把起钉器拔下来,还得把锯子折叠起来。
Laravel 11 的刀,就是一个光溜溜的刀片。你想切苹果?切。你想雕花?雕。它没有多余的累赘,没有沉重的背景,只有锋利的刃口。
最后的忠告:
当你打开 Laravel 11 的新项目时,别被它的简单吓到了。你会觉得:“怎么什么都没有?”
别担心。什么都没有,就是最好的设计。
删掉你不需要的 Service Provider,删掉你不需要的 Facade,删掉你不需要的复杂目录结构。
把你的代码写在路由里,写在控制器里,写在模型里。
这就是 Laravel 11 的奥义:少即是多。 它在帮你减负,让你从“框架的奴隶”变成“代码的主人”。
好了,今天的讲座就到这里。现在,去试试 php artisan serve,然后去 bootstrap/app.php 里写一个闭包路由,感受一下久违的自由吧!
下课!