使用依赖注入时,依赖项应单独传递给构造函数,还是可以传递整个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
这样的应用程序中,我看到依赖项被单独传递给构造函数。
有什么建议吗?
答案 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']);
};
您的课程更可重复使用,编写测试更容易。