控制匿名类的使用
根据匿名类的定义,它没有名称。不过,为了提供信息,PHP 信息函数(如 var_dump()
、var_ export()
、get_class()
和 Reflection
扩展中的其他类)将匿名类简单地报告为 class@anonymous
。然而,当一个匿名类扩展了另一个类或实现了一个接口时,让 PHP 信息函数反映这一事实可能会有些用处。
在 PHP 8 中,扩展了一个类或实现了一个接口的匿名类现在通过将分配给匿名类的标签更改为 Xyz@anonymous
(其中 Xyz
是类或接口的名称)来反映这一事实。如果匿名类实现了多个接口,则只会显示第一个接口。如果匿名类扩展了一个类,同时也实现了一个或多个接口,它所扩展的类的名称就会出现在标签中。下表总结了这些可能性:
上下文 | 新名称 |
---|---|
extends Xyz |
Xyz@anonymous |
implements Abc |
Abc@anonymous |
implements Abc, Def |
Abc@anonymous |
extends Xyz implements Abc |
Xyz@anonymous |
请记住,PHP 已经可以测试匿名类是否属于某一继承关系。例如,instanceof
操作符就可以用于此目的。下面的示例说明了如何测试匿名类的继承性,以及如何查看它的新名称:
-
在本例中,我们将定义一个
DirectoryIterator
实例,用于从当前目录抓取文件列表:// /repo/ch09/php8_oop_diff_anon_class_renaming.php $iter = new DirectoryIterator(__DIR__);
-
然后,我们将定义一个扩展
FilterIterator
的匿名类。在这个类中,我们将定义accept()
方法,该方法会产生一个布尔结果。如果结果为TRUE
,那么该项目将出现在最终迭代中:$anon = new class ($iter) extends FilterIterator { public $search = ''; public function accept() { return str_contains( $this->current(), $this->search); } };
-
接下来,我们将生成名称中包含
bc_break
的文件列表:$anon->search = 'bc_break'; foreach ($anon as $fn) echo $fn . "\n";
-
在接下来的两行中,我们将使用
instanceof
来测试匿名类是否实现了OuterIterface
:if ($anon instanceof OuterIterator) echo "This object implements OuterIterator\n";
-
最后,我们将使用
var_dump()
简单地转储匿名类的内容:echo var_dump($anon);
下面是在 PHP 8 下运行的输出结果。我们无法在 PHP 7 中运行此示例,因为该版本缺少 str_contains()
函数!
root@php8_tips_php8 [ /repo/ch09 ]#
php php8_oop_diff_anon_class_renaming.php
php8_bc_break_construct.php
php8_bc_break_serialization.php
php8_bc_break_destruct.php
php8_bc_break_sleep.php
php8_bc_break_scanner.php
php8_bc_break_serializable.php
php8_bc_break_magic_wrong.php
php8_bc_break_magic.php
php8_bc_break_magic_to_string.php
This object implements OuterIterator
object(FilterIterator@anonymous)#2 (1) {
["search"]=> string(8) "bc_break"
}
正如您所看到的,instanceof
正确报告匿名类实现了 OuterInterface
(因为它扩展了 FilterIterator
,而 FilterIterator
又实现了 OuterInterface
)。 您还可以看到 var_dump()
将匿名类的名称报告为 FilterIterator@anonymous
。
现在您已经了解了 PHP 8 中匿名类命名的变化,让我们看看命名空间处理方面的变化。