<?php
var_dump(php_uname('s'));
$base_dir = sys_get_temp_dir() . DIRECTORY_SEPARATOR;
file_put_contents($base_dir . 'Baz.php', "<?php namespace Foo\Bar; class BAZ {}");
file_put_contents($base_dir . 'Buz.php', "<?php namespace Foo\Bar; class Buz {}");
spl_autoload_register(function ($class) {
echo "Trying to autoload $class\n";
// project-specific namespace prefix
$prefix = 'Foo\\Bar\\';
// base directory for the namespace prefix
global $base_dir; # = __DIR__ . '/src/';
// does the class use the namespace prefix?
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
// no, move to the next registered autoloader
return;
}
// get the relative class name
$relative_class = substr($class, $len);
// replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require $file;
} else {
echo "Could not require $file\n";
}
});
// This works as expected because the class name matches the intended
// case in the file and as it is represented on disk.
$c1 = new \Foo\Bar\Baz();
// This works because PHP is PHP. This is not even going to hit the
// PSR-4 autoloader. The *usage* of this classname by the user is not
// PSR-4 compliant but that does not make the *autoloader* noncompliant.
$c2 = new \Foo\Bar\BAZ();
var_dump($c1 == $c2);
// This is going to be rejected by the PSR-4 autoloader implementation.
// That is fine *and expected* because the *usage* of the classname by
// the user is incorrect.
//
// On some platforms this may actually work but that is a byproduct of
// certain platforms not caring about case. But again, the *usage* of
// this classname *in this context* is not PSR-4 compliant.
//
// PSR-4 says that case is important and that case MUST be taken into
// account when creating the file path representing the class name. It
// also dictates that case MUST be taken into account when you create
// files on disk for the FQCN in question.
//
// If the FQCN is \Foo\Bar\Baz in src/Baz.php, then specifying the class
// with any other case than \Foo\Bar\Baz by the user is not compliant
// with PSR-4. This is a problem with the user using the wrong classname
// and the user should not expect this to work if they are following
// the documented case for the classes in question.
//
// In some cases the planets will align and allow this to work anyway.
// For instance, I think if you ran this on Windows it would actually
// work.
//
// All the autoloader implementation can do is *try* to ensure it is
// using the right case. If PHP / the platform discards that information
// it is out of scope of PSR-4.
$c3 = new \Foo\Bar\BUZ();
$c4 = new \Foo\Bar\Buz();
var_dump($c3 == $c4);
// In the end, the fact that PHP considers \Foo\Bar\Buz and \Foo\Bar\BUZ
// to be the same complicates things. This detail was ignored by PSR-0
// and it was one of the big things that people considered "bad" about it.
//
// The intent with PSR-4 is to ensure that people do not rely on the fact
// that PHP is fuzzy in its handling of case for classnames and namespaces
// and ensure that everyone uses the same case in all contexts for the
// same class.
//
// There ARE edge cases where PHP will allow things that it shoudln't, but
// PSR-4 autoloader implementations only need care about ensuring that it
// locates and loads files using the case for the classname given it. As
// long as this is the case, anything else PHP does weird is out of scope
// for PSR-4 autoloader implementations.
string(5) "Linux"
Trying to autoload Foo\Bar\Baz
bool(true)
Trying to autoload Foo\Bar\BUZ
Could not require /tmp/BUZ.php
Fatal error: Uncaught Error: Class "Foo\Bar\BUZ" not found in /in/U0J5m:80
Stack trace:
#0 {main}
thrown in /in/U0J5m on line 80
Process exited with code 255.
string(5) "Linux"
Trying to autoload Foo\Bar\Baz
bool(true)
Trying to autoload Foo\Bar\BUZ
Could not require /tmp/BUZ.php
Fatal error: Uncaught Error: Class 'Foo\Bar\BUZ' not found in /in/U0J5m:80
Stack trace:
#0 {main}
thrown in /in/U0J5m on line 80
Process exited with code 255.
string(5) "Linux"
Trying to autoload Foo\Bar\Baz
bool(true)
Trying to autoload Foo\Bar\BUZ
Could not require /tmp/BUZ.php
Fatal error: Class 'Foo\Bar\BUZ' not found in /in/U0J5m on line 80
Process exited with code 255.