# 3v4l.org

run code in 150+ php & hhvm versions
<?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, on Windows this actually "works." But just because it // "works" on Windows that does not mean it is correct. // // 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. The important thing is that if the author // of the class says that the class name is \Foo\Bar\Buz, the user of the // class needs to use it as \Foo\Bar\Buz. The user MAY use it with a // different case like \Foo\Bar\BUZ, in an some cases that MAY "work", but // whether the autoloader loads the class or not, the user's *usage* is // not compliant with 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. // // Authors need to ensure that if they write a package with a classname of // \Foo\Bar\Buz that they honor the case on the filesystem as well. If they // do not ( say [\Foo\Bar, src/] with "Foo\Bar\Baz" defined in src/BAZ.php ) // then their package is not PSR-4 compliant even if a PSR-4 autoloader may // sometimes load \Foo\Bar\Baz from src/BAZ.php on some platforms. // // Users of a class need to ensure that they use the correct case for any // class they load that is autoloaded by PSR-4. This means that if they use // a package that defines [\Foo\Bar, src/] with "Foo\Bar\Baz" in src/Baz.php, // they MUST call new \Foo\Bar\Baz() or their *usage* of the class is not // PSR-4 compliant, even if on some platforms they might get to load the // "correct class" with new \foo\bar\baz(). // I don't know if this will change any minds, but hopefully it helps reveal // the intent behind the case rules in PSR-4. The intention was to ensure // everyone is consistent in the case for FQCN specifically because PHP is // loose in how it handles case in some cases. // // An autoloader is not required to ensure that the case for the file it // includes matches the requested classname. It is only required to make a // reasonable effort to ensure that it uses the requested classname in // building the path to the file on disk that may contain the class in // question. // // An autoloader is only part of the PSR-4 equation. There are also class // authors and class users as well. The case rules apply to all to ensure // they are all speaking the same case.
Output for 7.0.0 - 7.1.0RC4
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/uGFbf:85 Stack trace: #0 {main} thrown in /in/uGFbf on line 85
Process exited with code 255.
Output for hhvm-3.10.0 - 3.12.0
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 undefined: Foo\Bar\BUZ in /in/uGFbf on line 85
Process exited with code 255.
Output for 5.3.0 - 5.6.21
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/uGFbf on line 85
Process exited with code 255.
Output for 5.2.3 - 5.2.17
Parse error: syntax error, unexpected T_FUNCTION, expecting ')' in /in/uGFbf on line 10
Process exited with code 255.
Output for 4.4.2 - 4.4.9, 5.1.0 - 5.2.2
<br /> <b>Parse error</b>: syntax error, unexpected T_FUNCTION, expecting ')' in <b>/in/uGFbf</b> on line <b>10</b><br />
Process exited with code 255.
Output for 4.3.0 - 4.3.1, 4.3.5 - 4.4.1, 5.0.0 - 5.0.5
<br /> <b>Parse error</b>: parse error, unexpected T_FUNCTION, expecting ')' in <b>/in/uGFbf</b> on line <b>10</b><br />
Process exited with code 255.
Output for 4.3.2 - 4.3.4
<br /> <b>Parse error</b>: parse error, expecting `')'' in <b>/in/uGFbf</b> on line <b>10</b><br />
Process exited with code 255.