单个文件中PHP类扩展的顺序

MTS*_*MTS 9 php subclass

在某些情况下,无序定义PHP类扩展会导致致命错误,而在某些情况下则不会。我正在尝试了解潜在的行为。

例如,两者

<?php
class BaseClass {}
class FirstExt extends BaseClass {}
Run Code Online (Sandbox Code Playgroud)

<?php
class FirstExt extends BaseClass {}
class BaseClass {}
Run Code Online (Sandbox Code Playgroud)

很好,所以不是简单地无序定义子类就不会引起问题。

但是,当涉及到三个类时(仅在一种特定情况下),即以相反的顺序定义类链时,就会出现错误。也就是说,以下代码将导致致命错误:

<?php
class SecondExt extends FirstExt {}
class FirstExt extends BaseClass {}
class BaseClass {}
Run Code Online (Sandbox Code Playgroud)

如果您尝试从命令行运行此命令(例如main.php),则会得到

PHP Fatal error:  Class 'FirstExt' not found in /path/to/main.php on line 2
Run Code Online (Sandbox Code Playgroud)

但是,三个类的其他五个顺序中的任何一个都没有错误。我很惊讶,即使

<?php
class SecondExt extends FirstExt {}
class BaseClass {}
class FirstExt extends BaseClass {}
Run Code Online (Sandbox Code Playgroud)

工作正常。区别因素是,在给出错误的情况下,所有三对可能的类对都是乱序,而在所有其他情况下,三对中的最多两对是乱序。

发生这种情况是怎么回事?

Don*_*nic 5

这种行为不是直观的,但我不认为这是一个错误,只是PHP加载类的方式的影响。

为了使类扩展父类,在定义子类时必须已经定义了父类。

根据我的观察,似乎在解析文件并开始执行之后,定义了以下类:

  • 内置类
  • 解析文件之前定义的所有用户定义类
  • 该文件中用户定义的基类
  • 该文件中的用户定义类扩展了已经定义的另一个类,该类可以早于该文件,也可以在该文件被解析之前

基本上,将在编译时定义任何类,并且在运行时定义(尝试)此时未定义的任何其他类。

因此,在此示例中:

<?php
echo class_exists('A') ? "Yes" : "No";   // No
echo class_exists('B') ? "Yes" : "No";   // Yes
echo class_exists('C') ? "Yes" : "No";   // Yes

class A extends B {}
class C {}
class B extends C {}
Run Code Online (Sandbox Code Playgroud)

当类A试图扩展它时就定义了类B,因为它是在解析文件时定义的,因为在文件中它是在类C之前定义的。

但是在这个例子中:

<?php
echo class_exists('A') ? "Yes" : "No";   // No
echo class_exists('B') ? "Yes" : "No";   // No
echo class_exists('C') ? "Yes" : "No";   // Yes

class A extends B {}
class B extends C {}
class C {}
Run Code Online (Sandbox Code Playgroud)

在类A尝试扩展它时未定义类B,因为在解析文件时未定义它,因为在文件中未在其之前定义类C。

PHP试图找到它,但是不会再次检入同一文件,而是试图自动加载它。那是当您得到“未找到”时。

添加第四个类,您可以看到它不仅发生在以相反顺序定义类时:

echo class_exists('A') ? "Yes" : "No";   // No
echo class_exists('B') ? "Yes" : "No";   // No
echo class_exists('C') ? "Yes" : "No";   // Yes
echo class_exists('D') ? "Yes" : "No";   // Yes

class A extends B {}
class D {}
class B extends C {}
class C extends D {}
Run Code Online (Sandbox Code Playgroud)