依赖注入 - 注入容器或个体依赖?

时间:2016-11-27 16:47:33

标签: php oop slim

使用依赖注入时,依赖项应单独传递给构造函数,还是可以传递整个DI容器?

例如......我有一个名为' UserRepository'的存储库。它包含以下方法:

<?php

namespace MyApp\Repositories;

use \MyApp\Models\User;

class UserRepository {

    private $ci;

    public function __construct($ci)
    {
        $this->ci = $ci;
    }

    public function hashPassword($password)
    {
        return password_hash($password, PASSWORD_BCRYPT, [
            'cost' => 15
        ]);
    }

    public function create($firstname, $lastname, $email, $password)
    {
        $user = User::create([
            'firstname' => $firstname,
            'lastname'  => $lastname,
            'email'     => $email,
            'password'  => $this->hashPassword($password)
        ]);

        return $user;
    }

    public function activateUser($userID)
    {
        $user = User($userID);
        $user->email_verified = 1;
        $user->save();

        $verification = $user->verification();
        $verification->is_used = 1;
        $verification->validated_at = $this->ci->get('Carbon')::now();
        $verification->save();
    }
}

Carbon依赖性可用,因为我已经传入Pimple容器。我可以通过这种方式访问​​任何依赖项(只要它们已经注册)。

我使用促进此类DI的Slim3。但是,在像Laravel这样的应用程序中,我看到依赖项被单独传递给构造函数。

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

将依赖注入容器传递给类时,将其称为“服务定位器”。使用服务定位器,您的类仍然负责实例化其依赖项,因此您还应该对其进行单元测试。但是怎么样?没有服务定位器,您的对象就不可能存在,并且测试起来并不容易。如果将依赖项传递给构造函数,则只需模拟它们即可。

在课堂上你有这个:

$verification->validated_at = $this->ci->get('Carbon')::now();

其中Carbon是服务名称。现在您应该记住,您注入到类中的服务定位器需要具有该名称的服务,并且它应该返回Carbon\Carbon类的实例。如果您的服务定位器缺少Carbon服务或者它返回一个完全不同的对象会怎么样?你应该用这样的东西进行测试,以确保不会破坏任何东西:

$this->assertInstanceOf(Carbon\Carbon::class, $container->get('Carbon'));

更重要的是,如果你想在其他地方重用你的对象,你需要实现一个特定的服务定位器实现。

通过使用DIC,您的对象不再负责实例化其依赖项:

$container['user.repository'] = function ($c) {
    return new UserRepository($c['Carbon']);
};

您的课程更可重复使用,编写测试更容易。