How does PHP's spl_autoload_register resolve circular dependencies with require_once?
php
Solution
Since your autoloader does - what its name says - auto load your classes, you dont need any other require then the one in the autoloader function.
If you use require_once instead of require in it, it will still only load it once, no matter if you extending from it or just create an object.
So just use the code you posted in your question and remove the require_once() in your animal.php since the autoloader already requires it.
Side note: If you dont want to deal with creating your own autoloader, you could use the composer autoloader. Its easy to install and very useful, because it deals with sub directories and makes you follow a strict namespace convention.
If you want to do so, you need to install composer first. Then, you create a file called composer.json in your base directory with following content
{
"autoload": {
"psr-4": { "YourProject\\": "src/" }
}
}
You then need to execute following command in your command line:
cd path/to/your/project
composer dump-autoload
If you have done it put your classes in basedirectory/src Note that you now have to give all classes a namespace, in this case if would be `namespace YourProject`. You are finally done!
Now go in your base directory and create a file, lets call it index.php:
require_once ('vendor/autoloader.php');
$a = new YourProject\Animal();
Sorry for long side note, sir!
Problem
How does PHP's spl_autoload_register resolve circular dependencies with require_once? Circular dependencies can be resolved some cases, but not all. Let's start with an example of when it fails. Suppose we have three classes defined in separate files: cat.php ``` class Cat extends Animal {} ``` animal.php ``` require_once('cat.php'); class Animal extends Creature {} ``` creature.php ``` class Creature {} ``` Let's say we also have a script that has an autoloader and creates an instance of Animal: run.php ``` spl_autoload_register(function($className) { require_once("$className.php"); }); $a = new Animal(); ``` Running this script with "php run.php" will result in a PHP Fatal error: PHP Fatal error: Class 'Animal' not found in .../Cat.php I think this makes intuitive sense to me, because of the circular dependency between Animal and Cat: - The autoloader attempts to load animal.php - Loading animal.php causes cat.php to load due to the require_once() - Loading cat.php fails becasue it extends Animal, and Animal can't be loaded twice by the autoloader. Here are some modifications to ensure that we don't get a fatal - animal.php should not have a require_once('cat.php') - This seems like the best solution as it effectively removes the circular dependency between Animal and Cat - Animal class should not extend Creature - Instead of using the Autoloader in run.php, just have a require_once() for both animal.php and creature.php Questions: - Why does #2 work? Why does Animal not extending Creature result in the resolution of the circular dependency between Animal and Cat? - Why does #3 work? Isn't the autoloader just doing a require_once() under the hood? The complete code (with some additional logging) from this examples can be found here