Yii 3.0 彻底移除 Service Locator,禁用 Yii::$app->db 等隐式访问,强制通过 PSR-11 DI 容器显式注册与构造函数注入依赖,未配置则运行时报错;需在 config/common.php 注册服务、控制器中声明类型提示依赖,并确保由容器实例化。

Yii 3.0 中已彻底移除服务定位器(Service Locator),不再支持 Yii::$app->db、Yii::$app->cache 等隐式访问方式,所有服务必须通过 PSR-11 兼容的 DI 容器显式注册并注入,否则运行时直接报错或类未找到。
确认你用的是 Yii 3.0 而非 Yii 2.x
执行 php -r "echo defined('YII_VERSION') ? YII_VERSION : 'not Yii';" → 若输出 3.0.x 或类似版本号,说明环境正确;若输出 2.0.45 等,则当前项目仍是 Yii 2.x,本指南不适用。
【Yii 3.0 不再定义 YII_VERSION 常量】 —— 实际上 Yii 3.0 已弃用该常量,此命令仅作快速甄别;更可靠的方式是检查 vendor/yiisoft/yii-core/composer.json 中的 "version" 字段是否为 "^3.0"。
用 DI 容器替代 Service Locator
第一步:在 config/common.php 中注册服务,例如数据库连接:
return [ 'yii\db\Connection' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=127.0.0.1;dbname=test', 'username' => 'root', 'password' => '', ],];
第二步:在控制器构造函数中声明依赖,而非调用 Yii::$app->get():
final class SiteController{ public function __construct( private \yii\db\Connection $db, private \Psr\Http\Message\ResponseInterface $response ) {}}
第三步:确保该控制器被容器自动解析——它必须作为路由目标被 DI 容器实例化,不能手动 new;否则依赖不会注入,$db 将为 null。
自定义服务注册的三种方式
方法一:绑定接口到具体实现(推荐用于解耦)
LoggerInterface::class => ['class' => FileLogger::class, 'logFile' => '@runtime/logs/app.log']
方法二:注册闭包工厂(需控制初始化时机)
CacheInterface::class => static function (\Psr\Container\ContainerInterface $container) { return new ApcuCache(['keyPrefix' => 'myapp_']);}
方法三:直接注入已存在对象(仅限测试或特殊场景)
DateTimeZone::class => new DateTimeZone('Asia/Shanghai')
【闭包内不可引用未声明变量】 —— 若闭包中用了 use ($config),必须确保 $config 在闭包定义时已存在且作用域有效,否则运行时报 Undefined variable。
排查“服务找不到”错误
① 运行 php yii serve 启动服务,观察终端是否报 Class not found 或 Cannot resolve service;
② 检查 config/common.php 是否被 Config/bootstrap.php 正确加载;
③ 执行 php -r "$c = require 'vendor/yiisoft/di/src/Container.php'; var_dump($c instanceof Psr\Container\ContainerInterface);" → 必须输出 bool(true),否则容器未启用;
④ 若使用属性路由(如 #[Route('GET /')]),确认对应控制器类名与文件路径严格匹配 PSR-4 规范,否则容器无法自动发现并注入。


















