不会。ThinkPHP 的 Env 类不自动加载 .env 文件,必须在 App::initialize() 前由 Dotenv::safeLoad() 显式加载,否则 env() 返回 null;CLI 模式需手动补载,且 .env 必须 UTF-8 无 BOM。

不会。ThinkPHP 应用初始化前,Env 类本身不自动加载 .env 文件,更不会把变量注入 $_ENV 或 getenv()。
为什么 env() 在 App::initialize() 前调用会返回 null
ThinkPHP 的 Env 类只是个读取器,它不负责加载——加载动作必须由 Dotenv 实例显式执行。框架默认只在 App::initialize() 阶段(即应用启动早期)调用一次 Env::load(),而这个调用本身又依赖于你是否已提前让 Dotenv 把 .env 解析进 PHP 环境。
常见翻车点:
- 在
bootstrap/app.php里直接写env('APP_DEBUG')→ 此时.env还没被读,env()返回null或默认值 - 在
config/database.php中写'hostname' => $_ENV['DB_HOST']→$_ENV是空的,报Undefined index - 误以为
think-env扩展会“自动生效”,其实它只提供工具,不插手生命周期
CLI 模式下尤其容易漏掉加载步骤
Web 请求中,public/index.php 启动流程隐含了 Env::load() 调用;但 CLI 模式(如 php think migrate)完全跳过这一步,除非你手动补上。
立即学习“PHP免费学习笔记(深入)”;
正确做法是在项目根目录下的 think 入口文件末尾插入:
if (PHP_SAPI === 'cli') {
$dotenv = \Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
}
注意几个硬性条件:
-
__DIR__必须指向项目根目录(含app/、config/、public/),不是public/或vendor/ -
.env文件编码必须是 UTF-8 无 BOM,否则safeLoad()静默失败 - 不能在
bootstrap/app.php里提前调用Env::get(),此时$dotenv->safeLoad()还没发生
怎么确认 .env 真的进了 PHP 环境
绕过 ThinkPHP 封装,直查底层:
- 命令行运行:
php -r "var_dump(getenv('APP_ENV'));"—— 若输出bool(false),说明Dotenv根本没加载成功 - 在命令类
handle()开头加:dump($_ENV['APP_ENV'] ?? 'not set', getenv('APP_ENV'));—— 两个都为空,就是加载路径或时机错了 - 不要依赖
php think env:list输出来判断,它可能缓存旧结果或仅显示 ThinkPHP 认为“有效”的键
真正关键的不是“有没有 env() 函数”,而是 Dotenv::safeLoad() 是否在任何配置解析之前被执行。一旦错过这个窗口,后续所有基于环境变量的配置(比如 config/database.php 里的 env('DB_HOST'))都会 fallback 到默认值,且毫无提示。



















