为什么使用嵌套特征会改变 PHP 行为?

Why does using nested traits change PHP behavior?

使用 PHP 7.2,我有一个使用特征 MyFirstTrait 的 class MyClass。它是这样定义的:

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 …

但是,如果我删除嵌套并从 MyFirstTrait 中删除 use 子句,脚本运行时不会出错。如果我先定义特征,然后再定义 class.

,也会发生同样的情况

在第一种情况下,文件如下所示:

// 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; }

为什么嵌套特征时行为会发生变化?

这对我来说意义不大,因为在这两种情况下,所使用的特征的定义都晚于它们被引用的时间。当去掉嵌套只使用单个trait时,在定义class.

之后再定义trait是没有问题的

从逻辑上讲,您引用的所有内容都应该在引用之前定义。不过也有一些例外。退一步说,一个PHP文件分两步解释:

  1. 标记化和解析。
  2. 解析代码的运行时执行。

一般来说、类会在runtime定义,意思是当代码按顺序执行时书面。在这里,您必须先在另一个特征 中定义要 use 的特征。 然而,一些 "simple" traits 和 类 可以在解析步骤中由解析器生成和定义,因此它们将在运行时 之前可用 。那纯粹是性能优化。

PHP 究竟是什么 "simple class/trait" 并不是我必须要记住或指望的东西,因为解析器的功能可能会从一个版本扩展到另一个版本(例如,在某些时候,像 static $foo = 4 + 2; 这样的语句支持简单的算术表达式,这在以前是一个解析错误)。