Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何处理类中的值对象?_Php_Dependency Injection - Fatal编程技术网

Php 如何处理类中的值对象?

Php 如何处理类中的值对象?,php,dependency-injection,Php,Dependency Injection,当我学习依赖注入时,我读到“每个”类依赖都应该被注入(现在我们忽略接口) 最近转向使用值对象而不是AssociationVee数组(在repo等中)。我读过的大多数教程都在类方法中实例化了值对象(没有依赖项注入)。这对于值对象来说不是什么大问题,但是为什么在repo构造函数中选择这个路径而不是注入依赖项,然后克隆空值对象呢 我不是在尝试微观优化,主要是在坚持和学习最佳实践 我能想到的避免克隆路由的唯一原因是构造函数注入值对象数据,但即使这样,克隆后也不能调用构造函数吗 例: VS 就我在阅读时理

当我学习依赖注入时,我读到“每个”类依赖都应该被注入(现在我们忽略接口)

最近转向使用值对象而不是AssociationVee数组(在repo等中)。我读过的大多数教程都在类方法中实例化了值对象(没有依赖项注入)。这对于值对象来说不是什么大问题,但是为什么在repo构造函数中选择这个路径而不是注入依赖项,然后克隆空值对象呢

我不是在尝试微观优化,主要是在坚持和学习最佳实践

我能想到的避免克隆路由的唯一原因是构造函数注入值对象数据,但即使这样,克隆后也不能调用构造函数吗

例:

VS


就我在阅读时理解您的问题而言,更多的是关于实例化对象的问题(更准确地说,不是类内部的新实例化)

在很多情况下,在
存储库中实例化对象是可以接受的。只是因为

这没什么大不了的

对于大多数简单的情况,当您已经实现了
Repository
应该返回的类时,让所有的db东西都实现为最新的(或者大约在那时)。这使得
存储库的测试不会因为要返回的类中的错误而失败,并且使这些测试更具功能性/集成性,而不是单元性

但可能还有更复杂的情况。一个例子是当返回的类(
User
,如果回答您的问题)被认为具有一些丰富的行为,因此使用了一些通过构造函数注入的服务。这将迫使
存储库
对完全不相关的事物拥有太多的知识,因此它可以实例化
用户
。另一个例子可能是开发人员不知道使用
Respository
获取的数据实例化什么和如何实例化的情况

这些情况迫使我们将所有这些无关的知识和功能从类中抽象出来,并将第三个对象注入
存储库
来完成这项工作。所以它可能看起来像:

interface UserFactoryInterface
{
    public function makeUserFromRawArray();
}


class Repo
{
    private $factory;

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

    public function getUser() {
        return $this->factory->makeUserFromRawArray($userDataProvidedByDB);
    }
}
因此,
UserFactoryInterface
的具体实现知道如何创建
User
,从数据库中获取原始数据并自行管理其他任何内容<代码>存储库
不依赖于它不应该依赖的东西,它只是从外部获取用于创建的服务


同样,我认为问题更多的是实例化对象和分离关注点的问题,而不是我更愿意为您发布的案例分别命名的问题。

值对象应该只包含属性(除了可能的构造函数、getter和setter)应用程序的其余部分使用的。如果要将其他一些值对象注入另一组属性,则应用程序很可能会以任何一种方式失败。空用户“值对象”/“实体”由数据库中的数据填充,并由repo返回。创建repo时,将注入
User
类的干净实例,这样每个克隆都是空的,就像它是在repo中实例化的一样。这里唯一的区别是在repo构造函数中注入干净的实体。(除非我误解了)让我们把它分解一下。1.repo总是需要返回具有完全相同属性集的对象,以便应用程序的其余部分知道它包含什么。2.值对象不包含任何业务逻辑,它(或至少应该)只在其属性中存储值。总之,模拟/更改值对象(将另一个值对象发送到构造函数中)意味着您仍然需要更改使用该值对象的所有代码(除非它具有相同的属性集,但为什么要更改它?)以使用新属性,然后DI就失去了它的用途
class Repo {

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

    public function getUser() {
        return (clone $this->user)->__construct($userDataProvidedByDB);
    }
}
interface UserFactoryInterface
{
    public function makeUserFromRawArray();
}


class Repo
{
    private $factory;

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

    public function getUser() {
        return $this->factory->makeUserFromRawArray($userDataProvidedByDB);
    }
}