本文代码
https://github.com/xialeistudio/yii2-di-demo
什么是依赖注入(DI)?
对象由框架来创建而不是程序员通过 new 创建。跟IoC差不多一个意思。
为什么要有依赖注入?
- 解耦。调用方不再通过 new 运算符实例化被调用对象,而通过框架(IoC容器)创建之后注入进来。解除了调用者与被调用者之间的依赖。
- 有利于面向接口编程。个人认为OOP程序设计最重要的就是面向接口(面向抽象)编程。因为有了第1步的关系,调用者只需要依赖接口类型而不用依赖实现类型,提高了程序的扩展性。
Yii2的依赖注入
Yii2通过 yiidiContainer 提供DI容器特性。目前支持一下4种方式注入:
注册依赖关系
- 通过容器的 set 方法注入
- 通过配置文件注入(推荐)
依赖注入实战
-
打开终端,执行以下命令初始化项目:
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
-
声明接口业务类 appservicesUserService
<?php namespace app\services; interface UserService { public function show($id); public function all(); }
-
接口实现文件 appservicesimplUserServiceImpl
<?php namespace app\services\impl; use app\services\UserService; class UserServiceImpl implements UserService { private $users = [ ['id' => 1, 'name' => 'xialei'], ['id' => 2, 'name' => 'zhangsan'], ]; public function show($id) { foreach ($this->users as $user) { if ($user['id'] == $id) { return $user; } } return null; } public function all() { return $this->users; } }
-
注册依赖关系 config/web.php
<?php use app\services\UserService; use app\services\impl\UserServiceImpl; $params = require __DIR__ . '/params.php'; $db = require __DIR__ . '/db.php'; $config = [ 'id' => 'basic', 'basePath' => dirname(__DIR__), 'bootstrap' => ['log'], 'aliases' => [ '@bower' => '@vendor/bower-asset', '@npm' => '@vendor/npm-asset', ], 'container' => [ 'definitions' => [ UserService::class => UserServiceImpl::class ] ], 'components' => [ 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '0xGrStOOZE2oXxNNiu-o2eYovJ_Ia1Dk', ], 'response' => [ 'format' => 'json' ], 'errorHandler' => [ 'errorAction' => 'site/error', ], 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [ ], ], ], ]; if (YII_ENV_DEV) { // configuration adjustments for 'dev' environment $config['bootstrap'][] = 'debug'; $config['modules']['debug'] = [ 'class' => 'yii\debug\Module', // uncomment the following to add your IP if you are not connecting from localhost. //'allowedIPs' => ['127.0.0.1', '::1'], ]; $config['bootstrap'][] = 'gii'; $config['modules']['gii'] = [ 'class' => 'yii\gii\Module', // uncomment the following to add your IP if you are not connecting from localhost. //'allowedIPs' => ['127.0.0.1', '::1'], ]; } return $config;
-
添加控制器 appcontrollersUserController
<?php namespace app\controllers; use app\services\UserService; use yii\base\Module; use yii\web\Controller; use yii\web\NotFoundHttpException; class UserController extends Controller { private $userService; public function __construct(string $id, Module $module, UserService $userService, array $config = []) { $this->userService = $userService; parent::__construct($id, $module, $config); } public function actionShow($id) { $user = $this->userService->show($id); if (empty($user)) { throw new NotFoundHttpException('用户不存在'); } return $user; } public function actionAll() { return $this->userService->all(); } }
-
运行测试服务器
./yii serve/index
-
访问用户列表接口 http://localhost:8080/user/all
[{ "id": 1, "name": "xialei" }, { "id": 2, "name": "zhangsan" }]
-
访问查看用户接口 http://localhost:8080/user/show?id=1
{ "id": 1, "name": "xialei" }
写在最后
如你所见,Yii2自带的IoC容器使用起来还是挺方便的,观测了Yii 配置优于编码 的思想,Yii的组件基本上都可以在配置文件中进行配置而不需要手动编码。
灵活使用DI可以使我们从依赖关系中解脱出来,专注于业务逻辑。
当然,业务逻辑的组织也是一个很大的研究课题,有兴趣的可以去看看 DDD(领域驱动设计)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。