Laravel — P48:依赖注入概念(高级 PHP 概念)

时间:2023-02-12 14:56:30

在你的 Laravel 职业生涯中,你会多次听到“依赖注入”这个词,所以你不妨熟悉一下它。在我们进入 Laravel 之前,让我们看看依赖注入作为 PHP(或任何编程语言)中的一个概念。

我们应该知道我们可以将对象作为参数传递给方法。我们也可以用继承类打hint,这是对PHP多态性的一个概述。我们可以将对象作为参数传递给构造函数。然后构造函数将在类中设置属性。这称为​​依赖注入​​。

在我的 PHP 教程系列中,我们研究了依赖注入。我们可以使用该代码来刷新自己。首先,让我们创建几个类:Lamborghini 和 Ferrari。这些类中的每一个都需要 Car 类。

<?php
require_once("Car.php");

class Lamborghini extends Car {

}
<?php
require_once("Ferrari.php");

class Ferrari extends Car {

}

我们现在可以创建我们的测试类并实例化这些对象。

<?php
// Object Arguments
require_once("Lamborghini.php");
require_once("Ferrari.php");

$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
$ferrari_f355 = new Ferrari(1996, "Ferrari", "F355");

你觉得上面的代码行得通吗?我们没有向 Lamborghini 和 Ferrari 类添加任何构造函数,但我们将参数传递给构造函数。信不信由你,它确实会起作用。为什么?因为我们已经在​​Car​​父类中定义了构造函数参数。如果我们的子类中没有构造函数,它会自动将参数传递给我们的父类。让我们快速浏览一下我们的​​Car​​类构造函数。

<?php
require_once('Vehicle.php');
require_once('Engine.php');
require_once('Transmission.php');

class Car extends Vehicle
{
use Transmission, Engine {
Transmission::check_oil_level insteadof Engine;
Engine::check_oil_level as check_engine_oil_level;
}

const HAS_HEADLIGHTS = true;
const HAS_TAIL_LIGHTS = true;
const HAS_TURN_SIGNALS = true;

private int $fuel_type;
private int $hp;
private int $tq;
private string $transmission;
private string $vehicle_type;
private bool $car_on;

public function __construct(int $year,
string $make,
string $model,
string $color = "",
int $fuel_type = 93,
int $hp = -1,
int $tq = -1,
string $transmission = "5 Speed Manual",
string $vehicle_type = "",
float $exterior_height = -1,
float $exterior_width = -1,
float $exterior_length = -1,
string $exterior_um = "in",
float $weight = -1,
string $weight_um = "lbs",
bool $car_on = false
)
{
$this->year = $year;
$this->make = $make;
$this->model = $model;
$this->color = $color;
$this->fuel_type = $fuel_type;
$this->hp = $hp;
$this->tq = $tq;
$this->transmission = $transmission;
$this->vehicle_type = $vehicle_type;
$this->exterior_height = $exterior_height;
$this->exterior_width = $exterior_width;
$this->exterior_length = $exterior_length;
$this->exterior_um = $exterior_um;
$this->weight = $weight;
$this->weight_um = $weight_um;
$this->car_on = $car_on;
}

//...
}

我们现在能做什么?我们可以访问父类中的所有属性和方法(只要它们不是私有的)。所以我们可以调用那些属性和方法。

<?php
// Object Arguments
require_once("Lamborghini.php");
require_once("Ferrari.php");

$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
echo $lamborghini_diablo->check_engine_oil_level();

$ferrari_f355 = new Ferrari(1996, "Ferrari", "F355");
echo $ferrari_f355->check_oil_level();

伟大的。我们还没有完成任何对象作为参数的传递。

我们要做的是创建一个​​Driver​​类。我们​​Driver​​类中的第一个方法将是​​drive()​ 方法,因为​​Driver​​应该可以​​drive()​ 开车。我们可以将​​Car​​对象作为参数传递给它,然后我们可以使用各种不同的​​Car​​方法来帮助我们驾驶汽车。我们将重点关注​​Car​​类中的两个方法是​​turnOn()​ 方法和​​drive()​ 方法。

<?php

class Driver {

public function drive(Car $car) {
echo $car->turnOn();
echo $car->drive();
}
}

我们现在可以回到我们的测试类并实例化对象。

<?php
// Object Arguments
require_once("Lamborghini.php");
require_once("Ferrari.php");

$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
$ferrari_f355 = new Ferrari(1996, "Ferrari", "F355");

$dino = new Driver();
$dino->drive( $lamborghini_diablo );

刚刚发生了什么?我以为我们指定我们必须将​​Car​​类型对象作为参数传递给​​drive()​​方法。它在​​drive()​ 声明中。

public function drive( Car $car )

这是你关于多态性的课程。由于我们的类​​Lamborghini​​和​​Ferrari​​类都扩展了​​Car​​类,从技术上讲它们是汽车!你猜怎么了?由于​​Car​​扩展了​​Vehicle​​类,从技术上讲,类​​Lamborghini​​和​​Ferrari​​类也是车辆!您想知道我们是否可以修改我们的声明以说明以下内容:

public function drive( Vehicle $vehicle )

答案是肯定的!你绝对可以。而且您仍会将 the​​$lamborghini_diablo​ 或​​$ferrari_f355​ 作为参数传递给该​​drive()​ 方法。如果我们将 传递​​$ferrari_f355​ 给我们的​​drive()​ 方法,我们将得到以下结果:​​Ferrari F355 has been turned on. I’m driving.​

现在让我们做一些不同的事情。​​int​我们创建了、​string​类型的类属性?只要看看​​Car​​类,您就会看到所有各种不同的属性。我们如何初始化这些属性?从构造函数。在实例化对象时,我们会将参数传递给构造函数,然后构造函数会使用作为参数传递的值来初始化这些属性。与我们将在课堂上所做的相同的概念​​Driver​​。我们将指定我们将拥有一个​​Car​​基于属性,并且我们将通过我们的构造函数传递一个​​Car​​参数并将其分配给我们的​​Car​​属性。请记住, a​​Car​​只是一种数据类型,例如​​int​​or ​​string​​。

<?php

class Driver {

private Car $car;

public function __construct(Car $car)
{
$this->car = $car;
}
}

我现在不想在这里失去你。请记住,一旦​​$car​ 通过我们的构造函数初始化了该属性,我们就可以访问我们所有的​​Car​​属性和方法,例如​​turnOn()​ 和​​drive()​​。因为我们知道我们必须将一种​​Car​​类型的对象传递给我们的构造函数并且它必须分配给我们的​​$car​ 属性,所以我们可以创建方法以预期我们将能够访问这些​​Car​​方法。所以,让我们​​drive()​ 在我们的类中重新创建我们的方法​​Driver​​。

<?php

class Driver {

private Car $car;

public function __construct(Car $car)
{
$this->car = $car;
}

public function drive() {
echo $this->car->turnOn();
echo $this->car->drive();
echo $this->car->turnOff();
}
}

你知道这是怎么回事吗?让我们在我们的测试文件中运行一个示例,然后遍历代码。

<?php
// Object Arguments
require_once("Lamborghini.php");
require_once("Ferrari.php");
require_once("Driver.php");

$lamborghini_diablo = new Lamborghini(1999, "Lamborghini", "Diablo");
$ferrari_f355 = new Ferrari(1996, "Ferrari", "F355");

$dino = new Driver( $ferrari_f355 );
$dino->drive();

$harrison = new Driver( $lamborghini_diablo );
$harrison->drive();

是时候进行彻底的代码遍历了。

  • PHP 进入测试类,需要​​Lamborghini​​, ​​Ferrari​​, 和​​Driver​​类。
  • 实例化了一个新​​Lamborghini​​对象,其类型为​​Car​​。
  • 由于​​Lamborghini​​该类不包含构造函数,因此调用父构造函数并将三个参数传递给父构造函数:​​1999​​, ​​Lamborghini​​, ​​Diablo​​。
  • 实例化了一个新​​Ferrari​​对象,它也是 类型​​Car​​。
  • 由于​​Ferrari​​该类不包含构造函数,因此调用父构造函数并将三个参数传递给父构造函数:​​1996​​, ​​Ferrari​​, ​​F355​​。
  • 创建一个新对象​​Driver​​并将该​​$ferrari_f355​​对象作为参数传递给构造函数。
  • 该类使用刚传递给它的对象​​Driver​​初始化了​​$car​​自身内部的属性。​​$ferrari_f355​​该​​$car​​属性现在可以访问 中的所有方法​​$ferrari_f355​​。
  • 该​​drive()​​方法被调用。
  • PHP进入​​drive()​​方法。它看到它正在调用 3 个不同的方法,所有方法都位于​​$car​​属性内,从技术上讲,这就是​​$ferrari_355​​对象。
  • PHP 执行​​turnOn()​​, ​​drive()​​, 和​​turnOff()​​方法。
  • ​Driver​​在测试文件中创建一个新对象,并将该​​$lamborghini_diablo​​对象作为参数传递给构造函数。
  • 该类使用刚传递给它的对象​​Driver​​初始化了​​$car​​自身内部的属性。​​$lamborghini_diablo​​该​​$car ​​属性现在可以访问 中的所有方法​​$lamborghini_diablo​​。
  • 该​​drive()​​方法被调用。
  • PHP进入​​drive()​​方法。它看到它正在调用 3 个不同的方法,所有方法都位于​​$car​​属性内,从技术上讲,这就是​​$lamborghini_diablo​​对象。
  • PHP 执行​​turnOn()​​, ​​drive()​​, 和​​turnOff()​​方法。

通过构造函数传递参数并将其分配给属性就是所谓的依赖注入

只要您想象参数如何在代码中移动的流程,我相信您会理解依赖注入。简单主题的复杂名称。

我们将在下一篇文章中解决 Laravel 对依赖注入的使用。