类与对象
PHP 类是一个包含代码的文件。类文件是一个实际存在于硬盘上的文件。如果你关掉电脑,然后再打开,类文件仍然存在。它包含的代码是在执行过程中创建对象的模板。类文件可以包含属性和行为。一旦类被实例化,属性就能在内存中保存数据。行为将由方法或函数处理。您可以使用访问器和突变器方法来更改类的属性值。
<?php
namespace Animal;
class Dog
{
public function returnSound(): string
{
return "Bark";
}
}
前面的示例类是一个 PHP 文件,其中包含命名空间声明、类名和一个名为 returnSound() 的方法或函数,该方法或函数返回一个 "Bark" 字符串。
另一方面,对象是类文件的实例。该对象物理上存在于计算机的 RAM 中,这是易失性存储器。这意味着如果您关闭计算机或停止程序,您就会丢失该对象。仅当您运行程序时才会创建该对象。
在 PHP 中,当您执行程序时,PHP 将从硬盘加载类文件,以创建临时存在于 RAM 中的对象实例。从字面上看,类是 PHP 在程序运行时创建对象的模板。
我们将使用一个消费者类来利用或使用 Dog.php 类,并使用一个变量来保存类的实例,该实例是一个对象:
<?php
namespace Animal;
class Display
{
public function outputSound()
{
$dog = new Dog();
echo $dog->returnSound();
}
}
Display 类是另一个类,可以将其视为消费者类或示例程序的起点。在这个类中,我们有一个 outputSound() 方法,用于 echo 对象的 returnSound() 方法的返回值。在 outputSound() 方法中,我们编写了 PHP 使用 new 关键字创建 Dog 类实例的指令:
当 PHP 执行 outputSound() 方法时,它将根据存储在计算机驱动器中的 Dog.php 类文件创建一个对象,然后将该实例或对象暂时存储在计算机内存中。$dog 变量将与 Dog 类实例或对象进行映射。无论何时使用对象的方法或属性,基本上都是从电脑内存而非 Dog.php 类文件访问对象。要进一步理解这一点,我们需要讨论一下 PHP 中的引用(References),这将在下一个小节中介绍。
现在,既然我们已经创建了一个 Dog.php 类文件的新实例并将其赋值给 $dog 变量,我们就可以访问 Dog 对象的方法、函数或属性了,这取决于它们的可见性。我们将在本章的 "OOP 中的封装" 部分讨论可见性。在我们的示例中,Dog.php 类的 returnSound() 方法被定义为 public,因此我们可以通过 Display.php 类的 outputSound() 方法访问该方法:$dog->returnSound();。
PHP 中的引用和对象
引用到底是什么?在 PHP 中,它是一个别名,或者说是一个或多个变量指向特定内容的一种方式。在前面的 Dog 对象示例中,我们创建了一个 Dog.php 类的实例,并将其赋值给 $dog 变量。$dog 变量本身并不包含 Dog 对象或实例的内存地址;它只是包含一个标识符,以便指向存储在内存中的 Dog 对象。也就是说,你可以让 $dog1 和 $dog2 变量指向同一个对象。让我们修改 Dog.php 和 Display.php 类来演示这一概念。
我们将这样修改 Dog.php 类
<?php
namespace Animal;
class Dog
{
private string $sound;
public function __construct()
{
$this->setSound("Bark");
}
public function returnSound(): string
{
return $this->getSound();
}
/**
* @return string
*/
public function getSound(): string
{
return $this->sound;
}
/**
* @param string $sound
*/
public function setSound(string $sound): void
{
$this->sound = $sound;
}
}
我们将修改 Display.php 类如下:
<?php
namespace Animal;
class Display
{
public function outputSound()
{
$dog1 = new Dog();
$dog2 = $dog1;
$dog1->setSound("Barky Bark");
// Will return "Barky Bark" which was set to $dog1.
echo $dog2->returnSound();
}
}
我们修改了 Dog.php 类,以便我们可以在实例化它后更改它返回的声音。在 Display.php 类中,您会注意到我们引入了一个新变量 $dog2,并为其分配了 $dog1。我们只有一个 Dog 对象实例,并且 $dog1 和 $dog2 变量具有相同的标识符并且引用相同的事物。这是代表这个概念的图表:
因此,如果我们运行 $dog2->returnSound(),它将返回我们在 $dog1 中设置的更新后的字符串,即使我们在将 $dog1 分配给 $dog2 后更改了 $sound 属性。
那么,如果您不希望 $dog2 受到 $dog1 属性发生的影响,但仍想创建该对象的副本或副本,该怎么办? 您可以像这样使用 PHP 的 clone 关键字:
<?php
namespace Animal;
class Display
{
public function outputSound()
{
$dog1 = new Dog();
$dog2 = clone $dog1;
$dog1->setSound("Barky Bark");
// Will return "Bark".
echo $dog2->returnSound();
}
}
这次,$dog2 将返回由其构造函数分配给 $dog1 的 $sound 属性的原始 Bark 字符串值。这是一个图表供您参考以理解这一点:
由于 $dog2 在 actor 改变 $dog1 的 $sound 属性之前就已被克隆,因此 $dog2 将保留旧值。无论 $dog1 发生什么,$dog2 都不会再自动发生,因为它们不再引用内存中的同一个对象:
总之,PHP 类是一个包含 PHP 能够创建对象的模板的文件。当使用 new 关键字并执行时,PHP 获取 class 文件并生成 class 文件的实例,并将其存储在计算机的内存中,这就是我们所说的对象。
现在我们已经阐明并解释了 PHP 中对象和类之间的区别,现在我们可以从抽象开始讨论 OOP 的四大支柱。