本文目录导读:

Laravel 的配置加载遵循一个分层覆盖的机制,优先级从高到低依次是:环境变量 (.env) > 服务提供者 / config() 动态设置 > 配置文件 (config/ 目录)。
具体加载顺序和执行阶段如下:
核心加载顺序(从启动到运行)
-
加载环境变量 (
.env)- 时机:在
bootstrap/app.php之后,但在加载任何配置文件之前。 - 文件:根目录下的
.env文件。 - 作用:使用
Dotenv组件将.env中的键值对加载到$_ENV和getenv()中。 - 关键点:
.env文件不会被直接读取为配置,而是作为配置文件的“数据源”。
- 时机:在
-
加载核心配置文件 (
config/目录)- 时机:在应用服务提供者注册之前。
- 文件:
config/app.php,config/database.php,config/cache.php等。 - 作用:Laravel 通过
Illuminate\Foundation\Bootstrap\LoadConfiguration引导程序,将config/目录下的所有 PHP 文件加载到Illuminate\Config\Repository中。 - 执行过程:
- 读取
config/目录下的所有.php文件。 - 将每个文件返回的数组放入
config仓库中,键名为文件名(app,database)。 - 在这个阶段,配置文件会读取
.env中的环境变量(例如通过env('DB_HOST', 'localhost'))。
- 读取
-
加载服务提供者 (Service Providers)
- 时机:在所有配置文件加载完毕后,Laravel 会遍历并注册
config/app.php中的providers数组。 - 作用:
- 注册阶段:服务提供者可以注册服务到容器,但它们通常不会修改配置。
- 引导阶段:关键覆盖点,服务提供者(特别是延迟加载的提供者)在
boot()方法中可以调用Config::set('key', 'value')来动态修改或覆盖配置。
- 优先级:服务提供者
boot()方法中设置的配置,会覆盖config/文件中静态定义的配置。
- 时机:在所有配置文件加载完毕后,Laravel 会遍历并注册
-
运行时设置 (
Config::set())- 时机:在应用运行期间(中间件、控制器、模型等)。
- 作用:通过
config(['key' => 'value'])或Config::set('key', 'value')动态修改配置。 - 优先级:最高,任何在运行时修改的配置,会立即覆盖之前在配置文件或服务提供者中设置的值。
关键优先级总结
| 优先级 | 来源 | 示例 | 说明 |
|---|---|---|---|
| 最低 | config/ 目录下的静态文件 |
config/mail.php |
基础默认值,会读取 .env 变量 |
| 中 | 服务提供者 boot() 方法 |
Config::set('mail.driver', 'log') |
在框架启动后、请求开始前被调用 |
| 最高 | 运行时 Config::set() |
config(['mail.driver' => 'array']) |
在控制器、中间件或测试中动态设置 |
一个具体的执行示例
假设你的 config/database.php 中含有:
'default' => env('DB_CONNECTION', 'mysql'),
在 app/Providers/AppServiceProvider.php 中的 boot() 方法有:
Config::set('database.default', 'sqlite');
实际运行结果:
.env文件中设置了DB_CONNECTION=pgsql,config('database.default')的值是sqlite(因为服务提供者覆盖了)。- 为什么? 因为服务提供者在
boot()中执行Config::set()的时刻,晚于配置文件读取.env的时刻。
常见陷阱与重要注意事项
-
不要在
config/文件之外使用env()辅助函数。- Laravel 官方文档明确建议:
env()函数*仅应在配置文件 `config/.php中使用**,一旦配置文件被缓存(php artisan config:cacheenv()函数在其他地方会返回null`。 - 正确做法:在配置文件里通过
env()获取值,然后其他地方通过config('key')获取。
- Laravel 官方文档明确建议:
-
配置缓存 (
php artisan config:cache) 的影响:- 当运行
config:cache时,Laravel 会合并所有config/目录下的文件成一个bootstrap/cache/config.php。 - 在缓存模式下,第1步和第2步被合并为一个快速加载。
- 服务提供者
boot()和运行时Config::set()依然可以覆盖缓存的值(因为缓存只是加快了配置文件加载速度,不锁定配置)。
- 当运行
-
环境变量优先级的实际体现:
- 尽管
.env文件在物理上先加载,但它的最终配置效果,取决于它在config/*.php文件中被引用的方式。 - 如果你直接写
'key' => 'hardcoded_value',则.env无法覆盖它。
- 尽管
总结流程图
启动应用
|
├── 加载 .env 文件 (将变量放入 $_ENV)
|
├── 加载 config/*.php (读取 $_ENV 获得值)
| |
| └── 得到初始配置数组
|
├── 注册服务提供者
| |
| └── 执行 boot() 方法 (可覆盖配置 - 第1次覆盖)
|
├── 发送请求 (中间件, 控制器)
| |
| └── 运行时 Config::set (可覆盖配置 - 第2次覆盖)
|
└── 响应请求
一句话总结:Laravel 配置是一个从磁盘文件向内存变量逐层加载、下层可以覆盖上层的单向过程,运行时动态修改的配置拥有最高优先权。