最简方式是直接改 index.php,但仅适用于单机调试;真正生效的是配置文件加载逻辑,需确保 config/ 下有对应环境文件及 main-local.php 的显式合并,init 脚本本质是复制预置配置而非动态切换。

直接改 index.php 是最简方式,但只适合单机调试
很多新手在本地跑 Yii 时,直接打开 web/index.php,把 YII_ENV 和 YII_DEBUG 改成 'prod' 和 false 就以为切到了生产环境——这确实能关掉调试栏、禁用错误堆栈,但**它不改变任何实际配置行为**。比如数据库还是连着你本地的 localhost:3306,日志还写在 @runtime/logs 下,缓存还是 FileCache。这种“伪切换”上线后必然出问题。
真正起作用的,是配置文件的加载路径和合并逻辑。Yii 不靠常量自动选配置,而是靠你手动组织文件结构 + 显式 require。所以别只改常量,重点看 config 目录下有没有对应环境的文件、main.php 里有没有 file_exists(.../main-local.php) 这类合并逻辑。
main-local.php 不是插件,是硬编码合并项
main-local.php 的存在完全依赖 main.php 末尾那几行代码:
if (file_exists(__DIR__ . '/main-local.php')) {
$config = yii\helpers\ArrayHelper::merge($config, require __DIR__ . '/main-local.php');
}
这意味着:
-
main-local.php必须和main.php在同一目录(通常是config/) - 文件权限要确保 Web 进程可读,Docker 部署时常见因
cp -r复制丢失权限导致静默失败 - 它不会被 Git 跟踪(通常已加在
.gitignore),所以每个环境部署时得单独传一份 - 如果你用 Composer 自动加载或自定义入口,绕过了
main.php的 require 流程,main-local.php就彻底失效
用 init 脚本切换环境,本质是复制预置配置
Yii Advanced 模板自带的 ./init 脚本不是动态切换,而是根据 environments/index.php 定义的规则,把对应环境下的 dev/web.php、prod/db.php 等文件,复制覆盖到 frontend/config/、backend/config/ 下。执行后你看到的是真实文件变更,不是运行时判断。
常见误操作:
- 执行
./init后没重新启动 Web 服务器(PHP-FPM 或 Apache),旧配置还在内存里 - 没注意脚本提示的 “Overwrite existing files?”,选了 yes 却忘了备份原
main-local.php - 在 Docker 中挂载了 config 目录,但
init复制的文件被挂载层覆盖,实际没生效
测试环境不能只靠 YII_ENV_TEST 常量
光定义 defined('YII_ENV') or define('YII_ENV', 'test'); 并不能让测试数据库自动生效。Yii 框架本身不内置“按环境自动加载 db-test.php”机制。你必须显式在 config/test/web.php 里写好数据库配置,再通过入口文件加载它,例如:
$config = require __DIR__.'/../config/test/web.php';
或者更稳妥的做法:在 config/main.php 里根据 YII_ENV 动态 require:
if (YII_ENV_TEST) {
$config = yii\helpers\ArrayHelper::merge($config, require __DIR__.'/test/db.php');
}
否则,YII_ENV_TEST 只会影响日志级别、调试组件开关等框架内置行为,对数据库、缓存、API 地址这些业务关键配置毫无作用。
多环境真正的复杂点不在“怎么切”,而在于“切完之后,哪些配置变了、哪些没变、谁负责保证它们同步”。尤其是 main-local.php 这种手动生成的文件,最容易在团队协作中漏传、错配、权限异常。每次上线前,建议用 grep -r "localhost\|127.0.0.1" config/ 快速扫一遍,确认没有开发地址残留在生产配置里。











