env() 读不到 .env 值是因为未显式加载或时机错误,而 config() 返回合并后的最终配置;.env 必须 utf-8 无 bom、在 autoload.php 后立即加载,且 cli 需单独处理。

env() 函数读不到 .env 里的值,但 config() 却能用
这是因为 env() 只读系统环境变量或 .env 文件(需 vlucas/phpdotenv 显式加载),而 config() 是框架层合并后的最终结果——它已经把 .env 解析值、配置文件默认值、运行时 set 全部揉在一起了。
常见错误现象:env('DB_PORT') 返回 false,但 config('database.hostname') 却是正确的。说明 .env 没被成功加载,或加载时机太晚。
-
.env必须在require __DIR__.'/../thinkphp/start.php';之前加载,推荐放在public/index.php中require __DIR__.'/../vendor/autoload.php';后立即执行 - 检查
.env文件编码:必须是 UTF-8 无 BOM,带 BOM 会导致Dotenv解析失败,所有键都读不到 - CLI 模式下(如
php think migrate)容易漏加载——入口脚本不是index.php,得在think命令文件里也补上$dotenv->load();
APP_ENV=dev 但 config/dev/ 下的配置不生效
ThinkPHP 的环境目录加载机制很“脆”:它只认 dev、test、prod 这三个小写固定值,且路径拼接严格区分大小写和命名规范。
典型失效场景:APP_ENV=development 或 APP_ENV=DEV → 框架直接跳过 config/ 下任何环境子目录,fallback 到根目录配置;config/prod/Database.php → 文件名大小写错误,静默忽略。
-
APP_ENV必须在 PHP 启动最早期定义,不能晚于autoload.php加载,否则环境识别失败 - 环境目录名必须全小写,且与
APP_ENV值完全一致(prod✅,production❌) - 每个环境子目录(如
config/prod/)至少要包含app.php、database.php、log.php等关键文件,空目录等于没配
如何让不同环境加载不同 .env 文件(如 .env.dev / .env.prod)
ThinkPHP 原生不支持多 .env 文件自动切换,但可通过 vlucas/phpdotenv 手动指定文件名实现,比硬编码更可控。
比如你想部署时用 .env.prod 而非通用 .env,就得在入口处显式传参,而不是依赖框架默认行为。
- 先确保
composer require vlucas/phpdotenv已安装 - 在
public/index.php中替换默认加载逻辑:$env = $_SERVER['APP_ENV'] ?? 'dev'; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__.'/..', '.env.'.$env); $dotenv->load();
- 注意:此时
.env文件本身会被忽略,只加载.env.dev或.env.prod,适合 CI/CD 流水线注入
部署后 env() 全失效,但线上又不能放 .env 文件
生产环境禁用 .env 是安全要求,但 env() 失效不代表配置就断了——只要你在 config/{env}/ 目录下写了对应配置,框架仍会走环境目录 + 默认值合并流程。
真正危险的是把敏感值(如数据库密码)写死在 config/database.php 里,或者指望 env() 在线上还能读到本地文件。
- 线上应通过 Web 服务器注入环境变量:Nginx 用
fastcgi_param APP_ENV prod;,PHP-FPM 池配置加env[DB_PASS] = "xxx" -
config/prod/database.php中不要调用env(),直接写明值或留空(由服务器变量兜底) - 验证是否生效:命令行执行
php think env,输出应显示服务器注入的变量,而非.env内容
env() 都是空的。最易被忽略的是 CLI 场景和服务器变量注入方式的不一致。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











