yii 3.0 必须使用 psr-11 容器(yiisoft\di\container)替代已移除的 yii\di\container,依赖需在 config/common.php 中注册,控制器通过构造函数注入,behavior 需显式传入依赖实例。

要在 Yii 3.0 中正确配置服务容器(IoC),必须绕过 Yii::$app、放弃 ServiceLocator 模式,直接使用 PSR-11 兼容容器注册依赖并显式注入——否则控制器无法解析、中间件启动失败、组件调用直接抛出 ReflectionException。
确认 PHP 版本与容器基础可用性
运行 php -v,确保输出版本号 ≥ 8.2;低于该版本会触发 【Fatal error: Uncaught Error: Call to undefined function yii\di\is_callable()】,且 composer create-project yiisoft/app 将立即退出,不生成任何文件。
执行 composer require yiisoft/yii-web 后,检查 vendor/yiisoft/ 目录下是否存在 yii-di 包——这是 PSR-11 容器的唯一实现,yii\di\Container 类已彻底移除,所有注入逻辑由 Yiisoft\Di\Container 承担。
全局容器配置入口:config/common.php
Yii 3.0 不再支持 config/web.php 返回数组,所有服务绑定必须写入 config/common.php,且返回格式为纯 PHP 数组或闭包组合:
return [ LoggerInterface::class => ['class' => FileLogger::class, 'logFile' => '@runtime/logs/app.log'], CacheInterface::class => RedisCache::class,];
注意:键名必须是接口或类的完整命名空间字符串,不能用字符串别名(如 'logger');值可以是类名字符串、关联数组(含构造参数)、闭包或对象实例——但【不支持 YAML 或 XML 配置】,任何非 PHP 原生语法都会导致容器初始化失败。
控制器中声明依赖的两种方式
方法一:构造函数参数自动解析(推荐)
在控制器类定义中,将依赖作为构造函数参数声明,类型提示必须精确匹配容器中注册的接口或类:
final class SiteController{ public function __construct( private LoggerInterface $logger, private ResponseInterface $response ) {}
这一步操作起来很简单,框架会在实例化时自动从容器中提取对应实例;若容器未注册 LoggerInterface::class,则抛出明确错误而非静默 null。
方法二:手动从容器获取(仅限特殊场景)
在需要动态解析或条件注入时,可通过 $this->getContainer()->get(SomeService::class) 获取,但【必须确保该服务已在 config/common.php 中注册,否则直接崩溃】;禁止在任意方法内调用 Yii::getContainer()——该静态方法已删除。
自定义 Behavior 的依赖注入改造
第一步:移除对 $this->owner->get('cache') 的调用
Yii 2.x 中常见的 Behavior 写法在 3.0 下完全失效,因为 $this->owner 不再继承 ServiceLocator,get() 方法不存在。
第二步:将所需依赖作为构造参数传入
final class CacheableBehavior extends Behavior{ public function __construct( private CacheInterface $cache, private string $keyPrefix = '' ) {}
第三步:在控制器或模型中注册 Behavior 时,必须传入已解析的依赖实例,不能只传类名:
public function behaviors(): array{ return [ 'cacheable' => [ 'class' => CacheableBehavior::class, 'cache' => $this->getContainer()->get(CacheInterface::class), ], ];}











