【问题标题】:PHP Can an injected object access properties of the object it was injected into?PHP 一个被注入的对象可以访问它被注入的对象的属性吗?
【发布时间】:2020-08-12 22:57:03
【问题描述】:

注入的对象是否有办法读取其父对象的属性?

这是一个例子:

这是一个field 对象,它包含字段的名称和值,并允许您注入验证规则:

class field
{
    public string $name;
    public $value;
    public array $validators;
    
    public function __construct($name, $value = null)
    {
        $this->name = $name;
        $this->value = $value;
    }
    
    public function addValidator(validatorInterface $validator): field
    {
        $this->validators[] = $validator;
        return $this;
    }
    
    public function validate()
    {
        foreach ($this->validators as $validator) {
            if (! $validator->validate()) {
                return false;
            }
        }
        return true;
    }
}

这里有几个验证器:

interface validatorInterface
{
    public function validate(): bool;
}


class stringValidator implements validatorInterface
{
    public function validate(): bool
    {
        return is_string($this->value);
    }
}

class lengthValidator implements validatorInterface
{
    public function validate(): bool
    {
        return strlen($this->value) > 3;
    }
}

现在让我们来测试一下:

$name = new field('name', 'Robert');
$name->addValidator(new stringValidator);
$name->addValidator(new lengthValidator);

echo $name->validate() ? 'valid' : 'invalid';

显然它失败了,因为验证器不知道field 对象的$value 属性是什么。

首先想到的是在每个验证器中创建一个 setter,field 对象使用它来将值传递给每个验证器:

class field
{
    [...]

    public function addValidator(validatorInterface $validator): field
    {
        $this->validators[] = $validator;
        $validator->setValue($this->value);                 // <--- new line
        return $this;
    }

    [...]

}

class stringValidator implements validatorInterface
{
    private $value;
    
    public function setValue($value): validatorInterface    // <--- new method
    {
        $this->value = $value;
        return $this;
    }
    
    public function validate(): bool
    {
        return is_string($this->value);
    }
}

但问题是,现在我需要遍历每个验证器,以便在新字段值发生更改时通知它们,这意味着 field 实例和 validatorInterface 实例都持有 @987654331 @ 那应该同步,但可能不是因为它们实际上不是同一个变量。

是否有任何直接的方法可以让注入的验证器“知道”field 实例的 value 属性是什么?

【问题讨论】:

  • 不,无法自动执行此操作。对象引用只有一种方式。而且一个对象可以在多个地方注入,你会参考哪一个?
  • 如果您需要这样做,您应该在包含该字段的验证器中添加一个属性,并将该字段传递给验证器构造函数。
  • 那么将字段注入到被注入字段的验证器中?
  • 是的,这样的交叉引用并不少见。
  • 那是我缺少的非直观部分。你让我重新考虑了我的整个策略;谢谢。

标签: php oop dependency-injection


【解决方案1】:

field object 传递给验证器而不是属性值,因为对象总是通过引用传递:

class field
{
    [...]

    public function addValidator(validatorInterface $validator): field
    {
        $this->validators[] = $validator->setField($this);
        return $this;
    }

    [...]

}

class stringValidator implements validatorInterface
{
    private $field;
    
    public function setField($field): validatorInterface
    {
        $this->field = $field;
        return $this;
    }
    
    public function validate(): bool
    {
        return is_string($this->field->value);
    }
}

你可以像你的例子一样使用它:

$name = new field('name', 'Robert');
$name->addValidator(new stringValidator);
$name->addValidator(new lengthValidator);

echo $name->validate() ? 'valid' : 'invalid';

可以在验证器的构造函数中传递 field 对象,但每次添加新验证器时都需要传递它,例如:$name-&gt;addValidator(new stringValidator($name)); 但上述解决方案更好.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多