env()读原始环境变量(如.env文件或系统变量),config()读框架合并后的运行时配置;前者直接、可控,后者结构化、有缓存,调试需对比二者差异定位问题。

env() 和 config() 看似都能取配置,但它们读的不是同一层东西——一个是“原材料”,一个是“成品菜”。理解这点,才能避免改了 .env 却没生效、或者清了缓存还读旧值的问题。
env() 读的是原始环境变量
它直接从系统环境变量或 .env 文件(需 vlucas/phpdotenv 支持)中提取键值,不经过框架配置系统,也不受 config/ 目录下 PHP 文件影响。
- 只认原始命名:env('APP_DEBUG') → 读 .env 里的 APP_DEBUG=true,不是 config/app.php 里的 app_debug
- 支持点号嵌套:env('database.host') 可读 .env 中的 DATABASE_HOST=127.0.0.1(前提是 .env 文件里用了下划线转点号的约定,或你已做映射)
- 带默认值很安全:env('REDIS_PORT', 6379) 如果没定义,自动回退为 6379,不会报错
- 注意:env() 不会自动把 .env 的值写进 config 系统,除非你在 config 文件里显式调用它,比如 'host' => env('DATABASE_HOST', '127.0.0.1')
config() 读的是合并后的最终配置
它返回的是框架启动时加载并合并过的“运行时配置快照”,来源包括:.env(经 env() 读取后)、config/*.php 文件、以及运行时手动 set 的值。
- 键名是配置路径:config('app.timezone') 对应 config/app.php 里的 timezone 键,不是环境变量名
- 有缓存机制:配置只在应用初始化时加载一次,后续修改 config/database.php 或 .env 并不会自动更新 config() 的结果
- 可临时覆盖:config('database.host', '10.0.1.5') 能在当前请求中覆盖该值,但不影响其他请求
- 无法感知未显式接入的 .env 项:如果 config/database.php 里没写 'host' => env('DATABASE_HOST'),那么即使 .env 里有 DATABASE_HOST,config('database.host') 也不会变
为什么有时 config() 有值,env() 却读不到?
常见于两种情况:
- 你看到 config('app.debug') 是 true,其实是因为 APP_DEBUG=true 在 .env 里,且框架早期把它映射到了 app_debug 配置项——但这属于特例(仅 APP_DEBUG 和 APP_TRACE 自动生效),不是 env() 本身读到了,而是框架内部做了桥接
- config() 返回的值可能来自 config/app.php 的硬编码,而非 .env;此时 env('APP_DEBUG') 返回 null,而 config('app.app_debug') 仍返回 true
怎么选?看用途
- 判断当前环境或快速取敏感值(如数据库密码)→ 优先用 env(),更直接、更可控
- 获取业务逻辑依赖的完整配置结构(如分页条数、上传路径)→ 用 config(),它已按规则合并,语义清晰
- 调试时怀疑配置没生效 → 同时查 env('KEY') 和 config('path.to.key'),对比差异,能快速定位是环境变量没加载,还是配置文件没引用它
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











