APP_ENV必须由系统环境变量或入口文件显式设置,不是从.env读取自动生效;它作为启动前开关决定加载config/dev/或config/prod/目录配置,若未提前设置,框架将fallback至默认配置。

APP_ENV 必须由系统环境变量或入口文件显式设置,不是靠 .env 文件自动生效
ThinkPHP 的 APP_ENV 不是从 .env 里读出来就自动切换环境的。它本质是一个启动前的“开关信号”,框架靠它决定加载 config/dev/ 还是 config/prod/ 下的配置文件。如果没在 PHP 进程启动前设好,后续所有配置(包括 APP_DEBUG、数据库地址)都会 fallback 到默认行为。
常见错误现象:dump(env('APP_ENV')) 输出 'dev',但页面仍不显示错误信息——说明 env('APP_ENV') 是从 .env 读到的,而框架真正用来选配置目录的是 getenv('APP_ENV'),后者可能为 false 或空字符串。
- CLI 模式下必须前置设置:运行
APP_ENV=prod php think run,不能只改.env后再执行 - Nginx/FPM 环境中,要在
fastcgi_param APP_ENV prod;中透传,且该行需放在include fastcgi.conf之后(否则被覆盖) - Apache 用户用
SetEnv APP_ENV prod,放在虚拟主机配置或.htaccess中,但注意.htaccess需开启AllowOverride All - Windows CMD 下不能用
set APP_ENV=dev && php think run(&&后的命令不在同一环境),应改用set APP_ENV=dev & php think run或 PowerShell
为什么 config/dev/ 和 config/prod/ 目录不能删
ThinkPHP 的多环境不是“换一个 .env 就切一套配置”,而是「三级配置合并」:基础配置(config/app.php)→ 环境目录配置(config/{APP_ENV}/app.php)→ .env 覆盖。删掉 config/dev/,哪怕 APP_ENV=dev 设对了,框架也会跳过这层,直接用基础配置 + .env,导致 APP_DEBUG=true 等关键项失效。
典型表现:APP_ENV=dev,但错误页面不显示 Trace;查 config/dev/app.php 会发现里面才真正写了 'debug' => true,而 config/app.php 默认是 false。
立即学习“PHP免费学习笔记(深入)”;
-
config/dev/和config/prod/必须全小写,不能是Dev/或PROD/ - 目录下只需放有差异的配置文件,比如只有
database.php和app.php,不用复制全部 - 首次部署后务必执行
php think clear:config和php think optimize:config,否则旧缓存会掩盖目录变更
CLI 命令(如 migrate、optimize)如何正确传入 APP_ENV
ThinkPHP 的 CLI 命令和 Web 请求共享同一套环境判断逻辑,但很多人只在 Nginx 里设了 APP_ENV,却忘了 CLI 是独立进程,不会继承 Web 服务器的环境变量。
错误做法:echo "APP_ENV=prod" >> .env && php think migrate —— 这只是改了 .env,但 think 入口脚本没读它,也不会触发目录切换。
- 必须在命令行前置设置:
APP_ENV=prod php think migrate - 若用 Windows PowerShell:
$env:APP_ENV="prod"; php think migrate - CI/CD 流水线中,应在 step 里显式 export:
export APP_ENV=staging && php think optimize:config - 别依赖
think\Env::set('APP_ENV', 'prod')在命令中动态设置——太晚了,配置系统早已初始化完毕
.env 文件本身只做变量覆盖,不决定环境切换
.env 的作用非常明确:在环境目录配置已加载的前提下,把同名键值覆盖进去。它不参与“选哪个目录”这个决策,也不影响 APP_ENV 的取值来源。
容易踩的坑:.env 里写了 APP_ENV=prod,但实际运行时还是 dev 环境——因为系统变量或 Web 服务器已设了 APP_ENV=dev,框架优先读系统变量,直接跳过 .env 中的 APP_ENV 行。
-
.env必须 UTF-8 无 BOM,放在项目根目录(和app/、config/同级) - 等号两侧不能有空格:
DB_HOST=localhost✅,DB_HOST = localhost❌ - 含特殊字符的值必须用单引号:
REDIS_PASSWORD='p@ss#123',双引号或不包都会解析失败 - 敏感字段如
DB_PASSWORD写完后立即执行:git rm --cached .env && echo ".env" >> .gitignore
最常被忽略的一点:APP_ENV 的值必须小写且严格匹配目录名,prod 可以,production 或 Prod 都会导致框架找不到对应目录,静默 fallback 到基础配置——这种问题没有报错,只有行为异常,排查起来最耗时间。



















