Order of PHP class extensions in a single file Order of PHP class extensions in a single file php php

Order of PHP class extensions in a single file


The behavior isn't intuitive, but I don't think it's a bug, it's just an effect of the way PHP loads classes.

In order for a class to extend a parent class, the parent class must already be defined when the child class is defined.

Based on my observations, it appears that after the file is parsed and execution begins, the following classes are defined:

  • built-in classes
  • all user-defined classes defined before the file was parsed
  • user-defined base classes in that file
  • user-defined classes in that file that extend another class already defined, either earlier in that file or before that file was parsed

Basically any class that can be defined at compile time will be, and any other classes not defined at that point will be (attempted to be) defined at run time.

So in this example:

<?phpecho class_exists('A') ? "Yes" : "No";   // Noecho class_exists('B') ? "Yes" : "No";   // Yesecho class_exists('C') ? "Yes" : "No";   // Yesclass A extends B {}class C {}class B extends C {}

class B is defined when class A tries to extend it, because it was defined when the file was parsed, because class C was defined before it in the file.

But in this example:

<?phpecho class_exists('A') ? "Yes" : "No";   // Noecho class_exists('B') ? "Yes" : "No";   // Noecho class_exists('C') ? "Yes" : "No";   // Yesclass A extends B {}class B extends C {}class C {}

class B is not defined when class A tries to extend it, because it was not defined when the file was parsed, because class C was not defined before it in the file.

PHP tries to find it, but it's not going to check in the same file again, it's going to try to autoload it. That's when you get "not found".

Add a fourth class and you can see it doesn't only happen when the classes are defined in reverse order:

echo class_exists('A') ? "Yes" : "No";   // Noecho class_exists('B') ? "Yes" : "No";   // Noecho class_exists('C') ? "Yes" : "No";   // Yesecho class_exists('D') ? "Yes" : "No";   // Yesclass A extends B {}class D {}class B extends C {}class C extends D {}