什么是类类型声明?

在 PHP 中,类类型声明是一种验证机制,用于确保我们的方法接收到了正确类型的对象。请相信我,这其实非常容易理解,如果需要,我也可以将它分解为更简单的形式来解释。

让我们描绘这样一个场景。想象一下,你正准备去商店购买你最喜欢的苹果品种——青苹果。你拿起购物车,径直走向水果区,专心地挑选那些新鲜、青翠的苹果放入购物车。就在你全神贯注地挑选时,发生了一件意想不到的事情。

在你未留意的一刹那,一个红苹果和一些芒果竟然悄悄地滚进了你的购物车。它们被困在那些青苹果之间,仿佛成为了你的“意外收获”。你继续挑选更多的青苹果,对自己的选择感到满意。

随后,你走到收银台,为你的商品付款。当收银员小心翼翼地清理购物车里的水果时,你突然发现那颗红苹果和芒果。你惊讶不已,心中不禁产生疑问:这些苹果和芒果是怎么混进来的?

哈哈,原来在你全神贯注购物时,它们悄悄“误入”了你的购物车,而你却浑然不觉。这个小小的插曲增添了几分生活的趣味性,也让你对自己的“粗心”感到好笑。

当你使用PHP构建应用程序时,就像在购物中心只将特定种类的苹果添加到购物车一样,你只想确保传递给方法的对象类型是你所期望的。我的朋友,你需要仔细检查并确保传递的对象类型正确无误,以保证程序的稳定性和正确性。

我们必须始终保证传入方法的对象属于正确的类型。类类型声明就起到了这个作用,防止了因类型不匹配而引发的错误。如果你还记得,我们之前提到过,类类型声明可以确保我们的方法接收到的对象是正确类型的。我们当然不希望发生这样的事情:明明需要传递一个苹果对象,结果却接收到了一个芒果对象。

类类型声明的优点在于,与购物中心中不想要的水果被放入购物车的情况不同,它能够快速有效地进行类型检查。当发现错误类型的对象被传递给程序中的方法时,它会自动发出警报,减轻了我们需要自己检查传递给方法的每个对象的压力。

这就是它的运作机制。当我们的程序开始运作时,它会立即扫描并验证所有传输的对象。一旦发现任何错误类型的对象,例如您在购物中心不需要的奇怪水果,它会立即抛出错误并通知您。

这种行为有助于我们在构建应用程序的过程中避免多种错误和问题。

我希望您已经对 PHP 中的类类型声明有了基本的了解。现在,让我们通过一些代码示例来加深理解。

在此示例中,我们将编写一个简单的程序,模拟一家汽车销售店的运营。

为了实现这个程序,我们需要创建一个类,这个类将具有一些方法,使我们能够添加汽车到我们的汽车销售店。

<?php

class CarShop
{
    public $cars = [];

    public function addCar($car): void 
    {
      $this->cars[] = $car;
    }
}

通过观察上述代码示例,您会发现,在我们的汽车商店类中,有一个名为 cars 的数组以及一个用于将汽车添加到 cars 数组的 addCar 方法。在上述示例中,我们并未进行任何特殊的类类型声明,只是按照常规方式进行操作。

既然我们已经明确了汽车商店类的定义,接下来我们需要确保能够将汽车添加到这些商店中。因此,我们需要创建一个 Car 类,以帮助我们创建汽车对象,并将这些对象传递给我们的汽车商店。以下是 Car 类的代码示例:

<?php

class Car
{
    public function __construct(public string $name, public string $color)
    {

    

} } 通过观察上述代码示例,您会发现我们的汽车类拥有两个属性:名称和颜色。有了这个类,我们现在能够创建Car对象,并将其添加到我们的汽车商店中。

接下来,我们将继续创建汽车并将其添加到我们的汽车商店。请参阅下面的代码:

<?php 

require_once  'CarShop.php' ; 
require_once  'Car.php' ; 

$car1 = new Car( "梅赛德斯 GLK""红色" ); 
$car2 = new Car("梅赛德斯 GLE ""绿色"); 
$car3 = “红色梅赛德斯奔驰” ;

从上述内容中,我们可以看出,已经创建了两辆汽车。一辆是红色的梅赛德斯 GLK,另一辆是绿色的梅赛德斯 GLE。另外,请注意,代码中还有一辆虚拟汽车。这只是一个带有“红色梅赛德斯奔驰”字样的字符串。创建这辆虚拟汽车的原因是为了强调类类型声明的重要性。接下来的代码示例中,我们将把这两辆车(包括虚拟汽车)添加到我们的汽车商店中。请查看下面的代码。

<?php 

require_once  'CarShop.php' ; 
require_once  'Car.php' ; 

$carShop = new  CarShop (); 
$car1 = new Car( "梅赛德斯奔驰" , "红色" ) ; 
$car2 = new Car( "梅赛德斯GLE" , "绿色" ) ; 
$car3 = "红色奔驰" ; 
$carShop -> addCar ( $car1 ); 
$carShop -> addCar ( $car2 ); 
$carShop -> addCar ( $car3 );

在之前的例子中,我们创建了一家新的汽车商店,并成功地将两辆车(假设其中包含至少一辆假车)添加到店中。但需要明确的是,我们并不希望在商店中出售假车。我之所以这样演示,是为了强调类类型声明的重要性。我们一直被假定不知道假车的存在,因此错误地将它添加到了我们的汽车商店。

未来某一天,我们可能会开始检查店里的每一辆汽车,并在代码中进行验证。以下是一个相关的代码示例:

foreach ($carShop->cars as $car)
{
    print $car->name;
}

如果您尝试遍历 cars 数组,您应该会得到以下结果

Mercedes BenzMercedes GLEPHP Warning:  Attempt to read property "name" on string in /file/…….

这里的问题在于,我们试图循环遍历一个汽车数组,但在成功循环前两辆车并打印出它们的名字后,PHP抛出了一个错误。原因是,它遇到了一个假车,并且无法继续循环,因为假车只是一个字符串,而不是一个真正的汽车对象。

为了解决这个问题,首先我们应该采取良好的编程实践,避免将假车放入汽车数组中。然而,由于缺少对类类型的检查或验证(例如类类型声明),假车被错误地添加到了汽车数组中。让我们修复这个问题,并看看下面的代码示例。

<?php

class CarShop
{
    public $cars = [];

    public function addCar(Car $car): void
    {
        $this->cars[] = $car;
    }
}

从上面的代码示例中,我们正在对汽车商店类进行修改,并向addCar方法添加类类型声明。此举的主要目的是确保所有添加到我们的汽车商店中的汽车都必须是汽车类别类型,正如您所看到的那样。简单来说,它必须是一个真正的Car对象,而不能是像之前的假奔驰那样的假对象。否则,PHP将会抛出错误。您可以通过查看下面的代码示例来了解这一点,这与我们之前的示例相同。

<?php


require_once 'CarShop.php';
require_once 'Car.php';

$car1 = new Car( "梅赛德斯奔驰" , "红色" ) ; 
$car2 = new Car( "梅赛德斯GLE" , "绿色" ) ; 
$car3 = "红色奔驰" ; 

$carShop = new CarShop();

$carShop->addCar($car1);
$carShop->addCar($car2);
$carShop->addCar($car3);

若你尝试运行上述代码,PHP 将抛出错误。这是因为在 addCar 方法中,我们添加了类类型声明,导致该方法强制要求只添加真正的汽车(即汽车类类型的汽车)到我们的汽车商店中。现在,让我们来看看 PHP 会抛出什么样的错误。

Fatal error: Uncaught TypeError: CarShop::addCar(): Argument #1 ($car) must be of type Car, string given, called in /Users/user/Desktop/blog-code-examples/class-type-declarations/class-type-declarations.php on line 15 and defined in /Users/user/Desktop/code—/class-type-declarations/CarShop.php:7

从您提供的错误信息中,我们可以看到PHP正在提醒您:您正在尝试将一个字符串传递给Car-shop,而不是预期的Car类类型的对象。

请按照以下步骤操作:首先,确保您正确地创建了一个Car对象实例。然后,将这个Car对象添加到您的汽车商店中。接下来,当您尝试循环遍历汽车时,这个Car对象将被“真实化”,这意味着它将被转换为实际的对象。您将会发现,如果遵循这些步骤,您的代码将会正常运行。