Peculiar Implications of Broken Class AutoloadersEdit

Now that we know a) that class autoloaders are broken and b) how they are broken, we can talk about the implications. A program crashing due to a non–existing class or file is not a big deal. It it easy to detect and easy to fix. The thing is, a faulty class autoloader can be a sole cause of difficult problems, symptoms of which suggest something completely different. Essentially, there are two scenarios. Not much, yet it does not make the problems any easier to understand and solve.

The first scenario is based on the mutability of the state and hooking techniques used in a program. Consider the following code. Note the time points, file and line marks reflecting the actual flow.

// Time point: 0, File: F1, Line: L1
// Register a storage class for autoloading.
// Note the capital W in MediaWiki namespace.
$wgAutoloadClasses['MediaWiki\NewStorage'] = 'includes/NewStorage.php';
// Hook a method to some event.
$wgHooks['SomeEvent'][] = 'MediaWiki\NewStorage::onSomeEvent';
// Time point: 1, File: F2, Line L2
// Method: SomeClass::someMethod()
// First reference to MediaWiki\NewStorage. Autoloader triggered.
// The lowercase w in the namespace is correct PHP and the condition
// would be true if the class was loaded with simple require.
// Yet, it will be false as a broken autoloader will not load this
// class at this moment.
if (class_exists('Mediawiki\NewStorage')) {
        $storage = MediaWiki\NewStorage::getInstance();
} else {                                    
        $storage = Vendor\Storage;          
// ... some logic with Vendor\Storage in mind.
wfRunHooks('SomeEvent', $this);
// Time point: 2, File: F2, Line: L3
// wfRunHooks() will result with second reference to MediaWiki\NewStorage
// as its method is hooked to SomeEvent. As the class has not yet been loaded
// autoloader will be triggered again. Only this time the class will actually
// be loaded. The reference matches the key in $wgAutoloadClasses.
        // Time point: 3, File F3, Line L4
        // We are in MediaWiki\NewStorage::onSomeEvent.
        // ... some magic with MediaWiki\NewStorage in mind.
        return true;
        // And we are getting back to file F2...
// Time point: 4, File: F2, Line L4
// ... logic with Vendor\Storage in mind continues.
return true;

Faulty class autoloader did not load MediaWiki\NewStorage class when SomeClass::someMethod() was called for the first time. Some parts of the code were executed with Vendor\Storage in mind, other parts with MediaWiki\NewStorage in mind which is a problem.

Let us assume there is another instance of SomeClass and SomeClass::someMethod() is called for the second time. The condition that evaluated to false at the time point 1, will evaluate to true, as the class is already loaded. The entire flow will be executed with MediaWiki\NewStorage in mind, as if Vendor\Storage never existed.