Tom Butler's programming blog

PHP Autoloaders should not be case sensitive

PHP Autoloaders

In its simplest case, an autoloader will load a file based on the class name:

function __autoload($className) {
     require_once 
$className '.php';
}

This allows the file MyClass.php to be loaded when this code is executed:

$obj = new MyClass;

However, if you're using a case-sensitive filesystem (such as most Unix/Linux and Mac filesystems), this code will not work:

$obj = new myclass;

This will error because the autoloader will try to load myclass.php instead of MyClass.php and fail. It's a minor problem in this trivial example but because PHP class names are not case sensitive this can create bizarre action at a distance

A side effect of this is that this code executes correctly:

$obj = new MyClass;
$obj = new MYCLASS;

Whereas this does not:

$obj = new MYCLASS;
$obj = new MyClass;

Should changing the order here really stop the code from executing? As long as an object is initialised with the correct case first, objects can then be initialised with the incorrect case afterwards.

Consider the following code:

function A() {
    
$obj = new MyClass;
}


function 
B() {
    
$obj = new myclass;
}


A();
B();

Because A is called first, this works fine and as expected. However, switch the order of the method calls and it becomes a problem:

function A() {
    
$obj = new MyClass;
}


function 
B() {
    
$obj = new myclass;
}

B();
A();

This creates confusing and counter-intuitive action at a distance. The developer now has to go and edit the B method to make the code work.

How can this be solved?

There are three ways this problem can be avoided

  1. Making the autoloader case-insensitive
  2. Always correctly referencing the class name with the correct case
  3. Making PHP enforce class name sensitivity

Let's examine each option individually

Making the autoloader case-insensitive

This is the most work for the autoloader developer and requires them to work around the case-sensitivty of the class names, for example ensuring that the case given to the autoloader does not effect whether or not the class can be loaded. This is a sensible option because PHP classes are case insensitive. Enforcing case-sensitivity in the autoloader causes potential issues

Always correctly referencing the class name with the correct case

This is a workaround more than a fix. In an ideal world, this would happen but PHP allows case insensitive class names, enforcing case sensitivity becomes an arbitrary restriction for developers. It's a workable solution but it's not ideal as it forces people to look up exact casing for a class (is it stdclass or stdClass? MySqli or MySQLi? that class you wrote a year ago called XmlFile.. or was it XMLFile?).

One minor issue this creates is consistency within projects when using third party libraries. If you're using PascalCase and library is using camelCase you have to remember the correct casing (which is visually inconsistent from the surrounding code) for classes of that library only

Making PHP enforce class name sensitivity

This is my preferred option, although it will never happen. If PHP inernally enforced case sensitivity it would fix the problem, it would have the same problem as above where you must remember the correct casing for the library, but it wold always error immediately and be a clear and obviously wrongly typed class name. It would prevent the action at a distance becasuse the scenario where commenting out a line of code that was correctly triggering the autoloader would not break an autoload call later on

It should be noted that PHP internals will never make this change. It would simply break far too much existing code and is not feasible.

So which is best?

The only viable and problem free option is to make the autoloader case insensitive. There are a few methods to do this.

The simplest is to enforce lowercase filenames. So MyClass is stored in myclass.php

function __autoload($className) {
     require_once 
strtolower($className) . '.php';
}

There other option is looping through the directory looking the filename ignoring the case, but that presents as many problems as it fixes, what if there is MyClass.php and myClass.php, which one should it load? Lowercase file names is the only consistent and logical answer.

Alternatively, you can make the autoloader first look for the correctly cased file, then the lowercase version:

function __autoload($className) {
    if (
is_file($className)) require_once $className '.php';
    else require_once 
strtolower($className) . '.php';
}

Conclusion

In short, there are zero benefits in making the autoloader case-sensitive and several drawbacks. There is no reason to make an autoloader case-sensitive.