Laravel 11+ 架构精简演进:分析其在减少底层脚手架开销与提升开发者心智负担方面的变革

各位同学,大家下午好!

我是你们的老朋友,那个在深夜里跟 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(...)

这导致了什么?架构的臃肿。 你的项目启动流程变成了这样:

  1. AppServiceProvider 启动。
  2. AuthServiceProvider 启动。
  3. EventServiceProvider 启动。
  4. 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.phpwithMiddleware 里配置,或者直接在路由闭包里加。代码即配置,配置即代码。

第三讲: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 时代,你想在本地跑个项目,通常怎么做?

  1. 打开 XAMPP/WAMP/MAMP。
  2. 启动 Apache/Nginx。
  3. 配置虚拟主机(Vhost),指向你的项目文件夹。
  4. 访问 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 里写一个闭包路由,感受一下久违的自由吧!

下课!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注