去评论
dz插件网

深入解析:PHP 继承中的构造函数

Crystαl
2024/08/23 01:09:13
您可能已经知道,继承是面向对象编程的核心原则之一,它允许子类继承父类的属性和方法。如果您对继承的概念还不够熟悉,我们为您准备了相关的文章供您深入了解。文章的链接已在上文提供。

现在,让我们聚焦于今天的主题:继承中的构造函数。简而言之,构造函数是一个特殊的函数,当创建类的对象时,它会自动被调用。

在子类继承父类时,关于构造函数的行为,有一个重要的点需要明确。那就是,如果子类有一个构造函数,并且父类也有一个构造函数,子类的构造函数并不总是需要显式地调用父类的构造函数。

但是,如果父类的构造函数需要一些必需的参数,那么子类的构造函数就必须使用相应的参数来调用父类的构造函数。这是因为,在某些情况下,代码的正常运行依赖于这些参数。

值得注意的是,如果子类的构造函数没有显式地调用父类的构造函数,PHP 将会自动尝试调用父类的构造函数(如果存在的话)。这种情况仅在父类的构造函数没有必需的参数时才会发生。

为了更好地理解这一点,我们可以使用学校作为类比。想象一下,我们有两种类型的学校:在线学校和实体学校。尽管它们的表现形式不同,但它们的共同目标是学习。无论是在线学习的学生还是参加实体课程的学生,他们都在学习。因此,在这个类比中,“学习”就像是父类构造函数中的必需参数,而在线学校和实体学校则是子类,它们可以选择显式地调用这个“学习”参数,也可以选择让 PHP 自动处理。

现在,让我们通过代码来展示这一过程。
<?php

class School
{
    public string $name;
   
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function study(): string
    {
        return "Studying";
    }
}

现在,我们来详细审视一下我们的基础类——School。在这个类中,我们可以观察到一个名为name的属性。此外,它还包含一个构造函数方法,用于初始化name属性。更值得一提的是,School类还定义了一个名为Study的方法。需要注意的是,在实例化School对象时,我们需要向构造函数传递相应的参数。

接下来,我们将目光转向另一个类。这个类代表了我们在线学校的一门课程。
<?php

class OnlineSchool extends School
{
    public string $platform;

    public function __construct(string $name, string $platform)
    {
        parent::__construct($name);
        $this->platform = $platform;
    }
}

现在,我们一起来深入学习这门课程。观察可知,OnlineSchool 类拥有一个名为 "platform" 的属性,这个属性代表了托管在线学校的平台,如 Udemy 等。此外,该类还包含一个构造方法,该方法接受两个参数:名称和平台。随后,这个名称被传递给另一个构造方法,而平台则被用来初始化 OnlineSchool 类的 "platform" 属性。

现在,让我为您详细解释一下这里发生了什么。实际上,这个过程相当直观易懂。在创建 OnlineSchool 对象时,我们需要提供两个关键信息:学校的名称和其所在的平台。这些信息通过构造方法被接收并处理,从而确保每个 OnlineSchool 对象都具有正确的标识和归属。通过这样的方式,我们可以轻松地对不同的在线学校进行管理和操作。
 parent::__construct($name);

只有在子类的构造函数中,当父类的构造函数需要特定参数时,我们才会显式地调用它。这是因为,如果父类构造函数没有必需的参数,PHP 将自动为我们处理调用过程,无需我们额外操作。回想我们之前的讨论,只有当父类构造函数需要必需的参数时,我们才需要在子类的构造函数中明确地调用它。这样,我们就可以确保从子类的构造函数中传递适当的参数给父类的构造函数。这样的做法确保了代码的清晰和高效,同时也保证了父类和子类之间的正确交互。
 parent::__construct($name);

通过简单地调用父类(School)的构造函数,并将所需的名称参数传递给它,就可以轻松实现继承。如果您对此还有印象,那么这就是我们的父类构造函数的模样。
 public function __construct(string $name)
 {
    $this->name = $name;
 }

请您仔细观察,这段代码中接受了一个名为“名称”的参数。当我们在子类的构造器中调用它时,只需要传递我们所需的名称给它即可。

现在,请您关注我们调用父级构造器的语法。

我们运用了“parent”关键字,结合范围解析运算符(::),随后调用了构造方法(__construct)。是的,就这么简单。
parent::__construct($name);

这就是如何调用父类构造函数的方法。请务必牢记,最佳实践是在子类构造函数中调用父类构造函数。

一旦成功调用了父类构造函数并传递了必要的参数,您就可以根据需求自由设置子类。在此场景中,我们仅需配置平台属性并为其指定一个值,如下所示:
 $this->platform = $platform;

现在运行我们的代码
<?php

require_once 'School.php';

require_once 'OnlineSchool.php';

$onlineSchool = new OnlineSchool("School of Coding", "Udemy");

print $onlineSchool->name;
print $onlineSchool->platform;

现在,就让我们一起深入探索吧。在这里,我们将实例化 OnlineSchool 类,并详细记录所传递的参数。首先,是名称参数,这一参数将被传递给父类的构造函数。紧接着,是平台参数,它将在 OnlineSchool 类中用于初始化我们的平台。我相信,通过下面的截图,您将能够更清晰地理解这一过程。



我正在使用 PHP Storm IDE,它能够清晰地展示“School of Coding”参数是如何映射到我们即将传递给父级构造函数的名称参数的。这种映射关系在代码中一目了然,使得开发者能够更轻松地理解和维护代码。
parent::__construct($name);

"udemy" 参数将被用于初始化 OnlineSchool 类中的平台属性,以便在后续操作中能够准确地标识和引用该在线学习平台。
$this->platform = $platform;

结果
School of Coding Udemy

如您所见,我们不仅能够轻松地打印出学校和平台的名称,更可以便捷地访问学习方法,其表现亦十分出色。

我希望您能充分理解,本课程的核心要义在于:一旦您注意到所继承的父类具有带有必要参数的构造函数,请务必调用它并传递相应的参数。

最后,我们将目光转向另一个类,深入探索它是如何调用父类构造函数的。这堂课程,将是我们的体育时光。
<?php

class PhysicalSchool extends School
{
    public string $location;

    public function __construct(string $name, string $location)
    {
        parent::__construct($name);
        $this->location = $location;
    }
}

正如您所观察的那样,PhysicalSchool 类不仅调用了其父类(Parent)的构造函数,而且还在其子类构造函数中传递了必要的参数。紧接着,在同一构造函数中,它继续初始化自己的属性(位置)。

现在,让我们执行我们的代码并查看运行结果,以深入了解这一过程的实际效果。
<?php

require_once  'School.php';

require_once 'PhysicalSchool.php';

$physicalSchool = new PhysicalSchool("School of Coding", "New Jersey");

print $physicalSchool->name;
print $physicalSchool->location;

在此处,您可以清晰地看到,我们首先传递了第一个参数,即名称,紧接着传递了第二个参数,即位置。

结果
School of Coding New Jersey