使用 PHP 7.2,我有一个类
MyClass
,它使用了特征 MyFirstTrait
。它的定义是这样的:
class MyClass
{
use MyFirstTrait;
}
这个
MyFirstTrait
使用了另一个特征MySecondTrait
。它的定义是这样的:
trait MyFirstTrait
{
use MySecondTrait;
}
MySecondTrait
不使用任何其他特征。它的定义是这样的:
trait MySecondTrait
{
}
如果我先定义
MyClass
,然后定义特征(特征定义的顺序并不重要),则会引发错误。
该文件将类似于:
// Not working
class MyClass { use MyFirstTrait; }
// These two lines can be swapped, the result is the same.
trait MyFirstTrait { use MySecondTrait; }
trait MySecondTrait { }
引发的错误是这样的:
Fatal error: Trait 'MyFirstTrait' not found in …
但是,如果我删除嵌套并从
use
中删除 MyFirstTrait
子句,则脚本运行时不会出现错误。如果我先定义特征然后再定义类,也会发生同样的情况。
在第一种情况下,文件将如下所示:
// Working
class MyClass { use MyFirstTrait; }
trait MyFirstTrait { }
第二种情况是这样的:
// Working
// These two lines can be swapped, the result is the same.
trait MyFirstTrait { use MySecondTrait; }
trait MySecondTrait { }
class MyClass { use MyFirstTrait; }
为什么当特征嵌套时行为会改变?
这对我来说没有多大意义,因为在这两种情况下,所使用的特征都是在引用之后定义的。当移除嵌套并且仅使用单个特征时,在定义类之后定义特征没有问题。
从逻辑上讲,您引用的所有内容都应该在引用之前定义。但也有一些例外。退一步来说,PHP 文件的解释分两步:
一般来说,类将在运行时定义,这意味着代码按照编写的顺序执行。在这里,您必须首先在另一个特征中定义要
use
的特征。但是,一些“简单”特征和类可以由解析器在解析步骤中生成和定义,因此它们将是运行前可用。这纯粹是性能优化。
PHP 到底将什么视为“简单的类/特征”,我不一定会尝试记住或依赖它,因为解析器的功能可能会从一个版本扩展到另一个版本(例如,在某些时候,简单的算术表达式变成了支持像 static $foo = 4 + 2;
这样的语句,这以前是一个解析错误)。