依赖注入——注入容器,还是独立的依赖?
Dependency Injection - Injecting The Container, Or Individual Dependencies?
使用依赖注入时,应该将依赖项单独传递到构造函数中,还是传递整个 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
容器。我可以通过这种方式访问任何依赖项(只要它们已注册)。
我正在使用 Slim3
来推广这种 DI。但是,在像 Laravel
这样的应用程序中,我看到依赖项被单独传递到构造函数中。
有什么建议吗?
当您将依赖注入容器传递给 class 时,您将其称为 "Service Locator"。使用服务定位器,您的 class 仍然 负责实例化其依赖项,因此您还应该对其进行单元测试。但是怎么办?如果没有服务定位器,您的对象就不可能存在,并且测试它并不容易。如果您将依赖项传递给构造函数,您可以模拟它们。
在你的 class 你有这个:
$verification->validated_at = $this->ci->get('Carbon')::now();
其中 Carbon
是服务名称。现在你应该记住,你注入 class 的服务定位器需要一个具有该名称的服务,它应该 returns Carbon\Carbon
class 的一个实例。如果您的服务定位器缺少 Carbon
服务或者它 returns 一个完全不同的对象怎么办?你应该用这样的东西测试它以确保不会破坏任何东西:
$this->assertInstanceOf(Carbon\Carbon::class, $container->get('Carbon'));
更重要的是,如果您想在其他地方重用您的对象,您需要实施特定的服务定位器实施。
通过使用 DIC,您的对象不再负责实例化其依赖项:
$container['user.repository'] = function ($c) {
return new UserRepository($c['Carbon']);
};
您的 class 可重用性更高,编写测试也更容易。
使用依赖注入时,应该将依赖项单独传递到构造函数中,还是传递整个 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
容器。我可以通过这种方式访问任何依赖项(只要它们已注册)。
我正在使用 Slim3
来推广这种 DI。但是,在像 Laravel
这样的应用程序中,我看到依赖项被单独传递到构造函数中。
有什么建议吗?
当您将依赖注入容器传递给 class 时,您将其称为 "Service Locator"。使用服务定位器,您的 class 仍然 负责实例化其依赖项,因此您还应该对其进行单元测试。但是怎么办?如果没有服务定位器,您的对象就不可能存在,并且测试它并不容易。如果您将依赖项传递给构造函数,您可以模拟它们。
在你的 class 你有这个:
$verification->validated_at = $this->ci->get('Carbon')::now();
其中 Carbon
是服务名称。现在你应该记住,你注入 class 的服务定位器需要一个具有该名称的服务,它应该 returns Carbon\Carbon
class 的一个实例。如果您的服务定位器缺少 Carbon
服务或者它 returns 一个完全不同的对象怎么办?你应该用这样的东西测试它以确保不会破坏任何东西:
$this->assertInstanceOf(Carbon\Carbon::class, $container->get('Carbon'));
更重要的是,如果您想在其他地方重用您的对象,您需要实施特定的服务定位器实施。
通过使用 DIC,您的对象不再负责实例化其依赖项:
$container['user.repository'] = function ($c) {
return new UserRepository($c['Carbon']);
};
您的 class 可重用性更高,编写测试也更容易。