Directory structure
learner@debian:~$ tree ~/bin
/home/learner/bin
└── php
├── Body
│ ├── Brain.php
│ └── Cell
│ └── Neuron.php
└── main.php
3 directories, 3 files
First code example
~/bin/php/main.php:
<?php
spl_autoload_register(function ($class) {
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
echo "----- Autoload $class from $path -----
";
include $path;
});
use Body\Brain;
$brain = new Brain();
?>
~/bin/php/Body/Brain.php:
<?php
namespace Body;
use Body\Cell\Neuron;
class Brain
{
public function __construct()
{
$this->brain = new Neuron();
$this->brain->talk();
}
}
?>
~/bin/php/Body/Cell/Neuron.php:
<?php
namespace Body\Cell;
class Neuron
{
public function talk()
{
echo "I am Neuron!
";
}
}
?>
I am able to execute main.php from my home directory in the following manner and it works fine:
learner@debian:~$ php ~/bin/php/main.php
----- Autoload Body\Brain from Body/Brain.php -----
----- Autoload Body\Cell\Neuron from Body/Cell/Neuron.php -----
I am Neuron!
I am surprised that this works. I expect it to fail when
$this->brain = new Neuron();
is executed in
~/bin/php/Body/Brain.php
. When this line is encountered, the
autoloader tries to execute include 'Body/Cell/Neuron.php'
but there
is no such subdirectory called Body
inside ~/bin/php/Body
.
Second code example
Let me show you why I expect the first code example to fail by showing another code example that is using include
statements instead of autoloader.
~/bin/php/main.php modified to:
<?php
include 'Body/Brain.php';
use Body\Brain;
$brain = new Brain();
?>
See that the autoloader is missing now from the above code, and the same include statement is being used now which was being executed by the autoloader earlier.
~/bin/php/Body/Brain.php modified to:
<?php
namespace Body;
include 'Body/Cell/Neuron.php';
use Body\Cell\Neuron;
class Brain
{
public function __construct()
{
$this->brain = new Neuron();
$this->brain->talk();
}
}
?>
Note that the same include statement has been added to this code that
was being executed by the autoloader earlier to load Body\Cell\Neuron
.
Trying to execute this code results in failure.
learner@debian:~$ php ~/bin/php/main.php
PHP Warning: include(Body/Cell/Neuron.php): failed to open stream: No such file or directory in /home/learner/bin/php/Body/Brain.php on line 4
PHP Warning: include(): Failed opening 'Body/Cell/Neuron.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /home/learner/bin/php/Body/Brain.php on line 4
PHP Fatal error: Class 'Body\Cell\Neuron' not found in /home/learner/bin/php/Body/Brain.php on line 12
This failure is expected because while executing
include 'Body/Cell/Neuron.php';
in ~/bin/php/Body/Brain.php
, it
doesn't find a subdirectory called Body
in ~/bin/php/Body
.
Question
I know that I can easily fix the second code example by editing
~/bin/php/Body/Brain.php
to use
include 'Cell/Neuron.php';
instead of
include 'Body/Cell/Neuron.php';
. However, my question is not about
why the second code example doesn't work, but about why the first code
example works.
- When the PHP interpreter is unable to
include 'Body/Cell/Neuron.php'
from~/bin/php/Body/Brain.php
in the second code example, how does the autoloader succeed in doing the same include from the same PHP file in the first code example? - Or am I mistaken? Could it be that in the first code example the
autoloader is always executing the include statements from
~/bin/php/main.php
regardless of where the classes are first being used, soinclude 'Body/Cell/Neuron.php'
is done at~/bin/php/main.php
and it succeeds because there indeed is a subdirectory calledBody
in~/bin/php
? If this is the case, where can I read about it in the official documentation? - To summarize our understanding, could you please tell me where the registered autoloader function is executed from, in general? From the script where the function is defined? From the script where the function is registered? Or from the script where a new class is encountered?