PHP面向对象编程中依赖注入、类型提示和组合的区别

6

我正在尝试学习PHP面向对象编程的概念,并观看了许多相关视频。其中很多视频都会展示像这样的示例:

class Person
{
    private $name;
    private $age;
    function __construct($name, $age)
    {
        $this->name = $name;
        $this->age = $age;
    }

}

class Business
{
    private $person;

    function __construct(Person $person)
    {
        $this->person = $person;
    }
}

问题在于,有时他们把这称为依赖注入,有时又称其为类型提示,第三次则将其作为组合。那么这个例子到底代表了什么?你能否解释一下它们之间的区别?


4
类型提示:在函数参数的变量前添加类型,例如(Person $person) - RiggsFolly
2
依赖注入:将Person对象传递给Business类的构造函数 - RiggsFolly
2
在Symfony 3.3中,对任何方法进行类型提示也提供了依赖注入:即使该方法可以使用全局服务。这非常令人困惑,措辞随处变化。 - RichieHH
2个回答

7
这是三个不同的概念: 类型提示是另外两个概念的基础,其包括在声明中为参数指定类型:
function cluefull(\Type $instance) {
    // I know that $instance is of \Type, I can safely use \Type methods on $instance
}

依赖注入 依赖于构造函数来定义对象生命周期和正确执行所需的所有依赖项。 这是一个关于依赖注入的相关讲话

class Foo {
    private $instance;
    public function __construct(\Type $instance) {
        $this->instance = $instance;
    }
}

组合是一种设计方向,它在可能的情况下与需要操作的实例进行组合,而不是从它们继承。因此,它既依赖于依赖注入,又依赖于类型提示。更多有关组合的阅读


据我所知,这也不完整。在Symfony中,在控制器中使用类型提示参数还会隐式创建服务注入,因为控制器使用该类型“提示”从容器中访问服务。 - RichieHH
1
@RichieHH 嗯...这个问题是关于面向对象编程,而不是Symfony。Symfony的主观观点并不是参考。"了解Symfony"和"了解OOP"并不相同。 - Félix Adriyel Gagnon-Grenier

-2

依赖注入是为您的应用程序提供其所需的任何数据,以使其正常运行。大多数应用程序都是模块化的,它们的行为类似于单独的组件或实体。但是所有应用程序都需要“接收”某些东西才能正常工作。

因此,它们需要的东西就是它们的依赖项。

这可以通过类构造函数传递,这是理想的,因为当对象初始化时,构造函数是首先调用的函数,因此可以通过构造函数传递应用程序需要的任何内容。但有时您也可以将数据直接作为参数传递给方法。例如:

# Generic Input validator
class InputValidator{
    function isEmailValid($email){}
}

# Our main application 
class UserRegistration(){
    function Register($inputValidator){
        $isEmailValid = $inputValidator->isEmailValid('foo@bar.com'); 
    }
}

# Instanciating the class and providing the dependancy
(new UserRegistration)->Register(new InputValidator()); 

在上面的例子中,UserRegistration->Register() 依赖于类 InputValidator() 来注册用户,我们本可以直接在 UserRegistration 类中提供电子邮件验证器,但我们选择将其作为依赖项传递,以使我们的应用程序整体符合 S.O.L.I.D。因此,简而言之,我们在那里注入了依赖项。这就是依赖注入。 类型提示 更容易理解。

基本上,如果我们扩展我们之前的例子并检查 Register(new InputValidator());,您可以看到我们传递给它所需的类,但有人错误地可能会传递另一个类或甚至是字符串,例如:Register('something'); 这将破坏应用程序,因为方法 Register 不需要字符串。为了防止这种情况,我们可以对其进行类型提示,换句话说,告诉 Register 函数仅接受某些类型的数据:数组、对象、整数... 或者我们甚至可以明确告知它要在之前提供一个类名来使用。

$InputValidator = new InputValidator(); 
Register(InputValidator $InputValidator);

关于组合,这篇文章比我能提供的更好阅读 什么是面向对象设计中的组合?


我猜测对于这行代码有问题的人是:"Register(InputValidator $InputValidator);" - RichieHH
@RichieHH 有兴趣改一下吗?我看不出这个有什么问题。 - samayo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接