3

本文代码

https://github.com/xialeistudio/yii2-di-demo

什么是依赖注入(DI)?

对象由框架来创建而不是程序员通过 new 创建。跟IoC差不多一个意思。

为什么要有依赖注入?

  1. 解耦。调用方不再通过 new 运算符实例化被调用对象,而通过框架(IoC容器)创建之后注入进来。解除了调用者与被调用者之间的依赖。
  2. 有利于面向接口编程。个人认为OOP程序设计最重要的就是面向接口(面向抽象)编程。因为有了第1步的关系,调用者只需要依赖接口类型而不用依赖实现类型,提高了程序的扩展性。

Yii2的依赖注入

Yii2通过 yiidiContainer 提供DI容器特性。目前支持一下4种方式注入:

  1. 构造方法注入
  2. 方法注入
  3. Setter和属性注入
  4. PHP回调注入

注册依赖关系

  1. 通过容器的 set 方法注入
  2. 通过配置文件注入(推荐)

依赖注入实战

  1. 打开终端,执行以下命令初始化项目:

    composer create-project --prefer-dist yiisoft/yii2-app-basic basic
  2. 声明接口业务类 appservicesUserService

    <?php
    namespace app\services;
    
    interface UserService
    {
        public function show($id);
        
        public function all();
    }
  3. 接口实现文件 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;
        }
    }
  4. 注册依赖关系 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;
  5. 添加控制器 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();
        }
    }
  6. 运行测试服务器

    ./yii serve/index
  7. 访问用户列表接口 http://localhost:8080/user/all

    [{
        "id": 1,
        "name": "xialei"
    }, {
        "id": 2,
        "name": "zhangsan"
    }]
  8. 访问查看用户接口 http://localhost:8080/user/show?id=1

    {
        "id": 1,
        "name": "xialei"
    }

写在最后

如你所见,Yii2自带的IoC容器使用起来还是挺方便的,观测了Yii 配置优于编码 的思想,Yii的组件基本上都可以在配置文件中进行配置而不需要手动编码。

灵活使用DI可以使我们从依赖关系中解脱出来,专注于业务逻辑。

当然,业务逻辑的组织也是一个很大的研究课题,有兴趣的可以去看看 DDD(领域驱动设计)


xialeistudio
21.5k 声望5k 粉丝