Composer Autoloader Features: Part 1

Like this article? Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Today we’re going to veer slightly away from Laravel, and take a look at Composer’s autoloading features. While Composer bills itself as a “Dependency Manager”, its real strength is that it gives PHP developers a standard environment to build their applications in.

That is, if you want to develop a PHP program that uses third party components, all you need to do is

  1. Install Composer

  2. Run composer require ..., composer install ..., composer update ...

  3. Include or require Composer’s autoloader in your program

For developers coming from other platforms, platforms where this sort of setup is handled by the language (Ruby/Python modules, C header files and linking, etc.), this may seem like a minor thing, but until Composer came along writing a non-trivial program in PHP meant learning each third party library’s autoloader system, include/require hell, or figuring out what sort of compromises the previous project developers made with regards to the same.

It’s not that Composer prevents third party libraries from creating the autoload hell of the past — it’s that Composer offers an autoloader system that’s good enough, and there’s little reason not to adopt it for greenfield development projects.

All that said — there’s a lot of legacy code out there, and adoption of the latest Composer and PSR autoloading standards is uneven. Add to that the fact that Composer development has been the red hot burning center of the PHP autoloading debate, and there’s plenty of misleading legacy debris lying around. As a PHP developer, you’ll often find yourself in situations where autoloader interaction is the root cause of a bug in your build system or framework of choice.

Understanding what Composer’s autoloader does is an important bit of knowledge to keep in your toolkit, whether you’re a developer interested in contributing to Composer, or just someone trying to get a job done using Composer managed code.

Composer’s Four Autoloaders and Code Generation

The first thing you’ll need to know about Composer autoloading is there’s actually four different autoloader methodologies. They are

  • PSR-0 autoloader
  • PSR-4 autoloader
  • A generic classmap autoloader
  • A “load this include file and do whatever you want to setup the autoloader” method

There’s also two different modalities to consider with the Composer autoloader. First, there’s using the Composer’s autoloader features as a package developer. Second, there’s using the autoloader features in a specific project not meant for redistribution. This second scenario is often called the “root” package.

Put another way, the Doctrine core team has a composer.json file for Doctrine, which includes configuration for autoloading Doctrine classes. However, you, as a developer building a business application using Laravel also have your own composer.json file, which you can configure to take advantage of Composer’s autoloader features for your own code.

While the syntax is identical for these two modalities, there’s differences to the paths generated. The first scenario needs to load from a package’s vendor/namespace/package-name folder, and the second needs to load from the root project folder.

Composer’s autoloader also relies heavily on code generation. Rather than search the entire directory tree for a class file every time, Composer auto-generates include files that contain all the information needed to include a class definition file. These files are mostly located and generated in the Composer vendor folder,

vendor/composer/autoload_classmap.php
vendor/composer/autoload_files.php
vendor/composer/autoload_namespaces.php
vendor/composer/autoload_psr4.php
vendor/composer/autoload_real.php
vendor/composer/include_paths.php

with the root autoload.php file located in the vendor folder

vendor/autoload.php

Many developers are surprised to learn Composer generates autoload files — that’s because this usually happens behind the scenes. When you add a new package to your project or update a version, Composer regenerates these files behind the scenes. However, you can (are are sometimes required) to rebuild the generated files by running the

$ composer dumpautoload

command. We’ll talk more about dumpautoloader later.

Using the Composer Autoloader

If you want to use Composer’s autoloader in your project, all you need to do is include the base Composer autoloader file.

include 'vendor/autoload.php';
#require 'vendor/autoload.php';
#include_once 'vendor/autoload.php'
#require_once 'vendor/autoload.php'

If you’re using a framework like Symfony, Zend, or Laravel, the framework may handle this for you. If not, you’ll need to use include, require, include_once, or require_once to load this file into your program.

If you take a look at this file’s content, you’ll see something like this

#File: vendor/autoload.php
// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInit1d454b6a6f83c27dc0634c7142f32df1::getLoader();

The first two lines are pretty self explanatory

#File: vendor/autoload.php    
// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

The comment notifies anyone looking at this file that it’s an auto-generated file. The implication here is “don’t edit this file and expect your changes to stick”. The second line requires in the generated autoload_real.php file.

The third line is a little weird —

#File: vendor/autoload.php    
return ComposerAutoloaderInit1d454b6a6f83c27dc0634c7142f32df1::getLoader();

This line calla the static getLoader method on the the ComposerAutoloaderInit1d454b6a6f83c27dc0634c7142f32df1 class. Why the goofy class name? Because this is a generated class file — you’ll find its definition in the autoload_real.php file

#File: vendor/composer/autoload_real.php
// autoload_real.php @generated by Composer

class ComposerAutoloaderInit1d454b6a6f83c27dc0634c7142f32df1
{
    //...
}

Whenever Composer generates a class file, it appends a unique identifying hash string to the end of the name (1d454b6a6f83c27dc0634c7142f32df1 above). This helps Composer developers when they’re working with the autoloader code, and also has the side benefit of making sure no library developers try calling these methods on their own (since the hash isn’t easily guessable). In some ways, a generated class file with a per-generation unique name is the ultimate private method.

The getLoader method in this class is where Composer instantiates its autoloader. We’ll talk more about this later, but for now let’s move on to Composer’s actual autoloader implementations.

Autoloader Include Files

We’re going to start with the simplest autoloader type in Composer, the file autoloader.

The file autoloader isn’t, strictly speaking, an autoloader. Instead, it’s intended as a legacy mechanism for libraries and frameworks with their own autoloading functionality that can’t (or won’t) be converted into a classmap or PSR autoloader.

To take advantage of the files autoloader, simply add an array of file names to your composer.json.

#File: composer.json    
{
    //...
    "autoload": {
        "files": ["path/to/file.php","path/to/second/file.php"]
    },
    //...        
}

When you run composer dumpautoload, (or when Composer runs it automatically during an update or install), Composer will look through all the packages composer.json files, as well as your main project composer.json files for the files autoloaders, and use them to generate the autoload_files.php file.

A generated autoload_files.php might look like this.

#File: vendor/composer/autoload_files.php
<?php    
// autoload_files.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    $vendorDir . '/ircmaxell/password-compat/lib/password.php',
    $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
    $vendorDir . '/phpseclib/phpseclib/phpseclib/Crypt/Random.php',
    $vendorDir . '/laravel/framework/src/Illuminate/Support/helpers.php',
);

As previously mentioned, in order to take advantage of Composer’s autoloader, a PHP program or framework needs to include/require the vendor/autoload.php file.

#File: vendor/autoload.php
<?php    
// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInit58ab3186241c31e404c0020afdf07dd0::getLoader();

If we take a look at the definition of getLoader, we’ll see the following near the end of the method

#File: vendor/composer/autoload_real.php
//...
public static function getLoader()
{
    //...
    $includeFiles = require __DIR__ . '/autoload_files.php';
    foreach ($includeFiles as $file) {
        composerRequire58ab3186241c31e404c0020afdf07dd0($file);
    }        
    //...
}    
//...
function composerRequire58ab3186241c31e404c0020afdf07dd0($file)
{
    require $file;
}

Here Composer loads its generated autoload_files.php files, and simply requires each file from the array.

While not exactly forward thinking, the files autoloaders are an important part of Composer’s adoption strategy. Convincing existing framework developers to convert years of code over to a PSR or classmap autoloader is going to be, in many cases, a non-starter. By creating this files mechanism, the Composer team gives existing library developers a clear path forward for using their autoloaders in a Composer based project. We’ll have more to say about this in a future article, when we look at the implementation of the SwiftMailer’s autoloader.

There are, of course, unintended consequences. When many system system and library developers discover the files autoloader mechanism, they see it as a perfect opportunity for some additional framework bootstrapping. Consider this section of Laravel’s composer.json

#File: composer.json    
"autoload": {
    //...
    "files": [
        "src/Illuminate/Support/helpers.php"
    ],
    //...
},

Here we see Laravel 4.2 uses the files autoloader to automatically include the src/Illuminate/Support/helpers.php file. The helpers.php file has nothing to do with class autoloading — it’s the file where Laravel defines its global helper functions (like array_add, e, link_to, etc.). Laravel isn’t alone in this — many packages overload the files autoloader for other purposes. At this point the Composer documentation embraces this use of the files autoloader, and it can be a little confusing to an experienced PHP developer who thinks “autoload == classes”.

As a systems developer, it’s important to remember that creative developers are going to use your features for things you never intended.

Classmap Autoloader

Next up the chain is the classmap autoloader. This autoloader is easy to understand. If you take a look at the generated file autoload_classmap.php

#File: vendor/composer/autoload_classmap.php

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    //...
    'PHPUnit_Extensions_GroupTestSuite' => $vendorDir . '/phpunit/phpunit/src/Extensions/GroupTestSuite.php',
    'PHPUnit_Extensions_PhptTestCase' => $vendorDir . '/phpunit/phpunit/src/Extensions/PhptTestCase.php',
    'PHPUnit_Extensions_PhptTestSuite' => $vendorDir . '/phpunit/phpunit/src/Extensions/PhptTestSuite.php',
    'PHPUnit_Extensions_RepeatedTest' => $vendorDir . '/phpunit/phpunit/src/Extensions/RepeatedTest.php',
    'PHPUnit_Extensions_TestDecorator' => $vendorDir . '/phpunit/phpunit/src/Extensions/TestDecorator.php',
    'PHPUnit_Extensions_TicketListener' => $vendorDir . '/phpunit/phpunit/src/Extensions/TicketListener.php',
    //...
);

you’ll see a PHP array where each key is a class name, and each value is a full file path to the class definition. Remember the findFile method from last time?

#File: vendor/composer/ClassLoader.php
public function findFile($class)
{
    //...

    // class map lookup
    if (isset($this->classmap[$class])) {
        return $this->classmap[$class];
    }

    //...
}

The classmap object property is the same array that’s in autoload_classmap.php. The Composer autoloader loads this map in the getLoader method.

#File: vendor/composer/autoload_real.php
public static function getLoader()
{
    //...
    $classmap = require __DIR__ . '/autoload_classmap.php';
    if ($classmap) {
        $loader->addClassMap($classmap);
    }
    //...
}

You can find the addClassMap method (called above) in the base ClassLoader class.

#File: vendor/composer/ClassLoader.php
public function addClassMap(array $classmap)
{
    if ($this->classmap) {
        $this->classmap = array_merge($this->classmap, $classmap);
    } else {
        $this->classmap = $classmap;
    }
}

The classmap is another popular PHP autoloader pattern. Rather than dynamically generate a class name each time a program instantiates a new class (which will include several string concat, replace, etc. combinations), with a classmap you can be explicit about the location of each class definition.

If you want to use a classmap autoloader in your Composer package or Composer based project, you can add a classmap node to the autoload node in your composer.json file.

#File: composer.json
"autoload": {
    "classmap": [
        "path/to/class/File_With_Class.php",
    ]
},

and then run

$ composer dumpautoload

Composer will generate a classmap array something like the following (for a package)

#File: vendor/composer/autoload_classmap.php
return array(
    //...
    'File_With_Class' => $vendorDir . '/vendor-name/package-name/path/to/class/File_With_Class.php',
    //...
);

or something like this (for a project)

#File: vendor/composer/autoload_classmap.php    
return array(
    //...
    'File_With_Class' => $baseDir . '/path/to/class/File_With_Class.php',
    //...
); 

In other words, Composer will insert your specified class definition file with the package folder, or project folder, prepended with the base vendor directory, or the base project directory, depending on the context of the composer.json file.

Important: Composer does not generate the array key (i.e. the class name, File_With_Class above) from the class’s file name. Instead, the Composer core code actually scans and reg-ex parses the file for any class names, interface names, or trait names.

One downside of a classmap is, you need to build and maintain the classmap. Having an additional step for a programmer to complete anytime they need to create a new class can be a block to productivity. Fortunately, Composer has a solution for this.

#File: composer.json
"autoload": {
    "classmap": [
        "path/to/class/folder",
    ]
},

That is, the classmap autoloader type also supports adding folders. If you add a folder, and then run

$ composer dumpautoload

Composer will scan the entire directory hierarchy of the configured path for class definition files. Specifically, Composer will search for files with the .php, .inc, or .hh file extension, and then search them for class definitions using the same findClasses method we linked to above. If you’re curious where the scanning happens in Composer’s source, checkout the createMap method.

Important: In case its not obvious from above — the code that generates these Composer autoloader include fiels is not a part of your vendor tree. It lives in the Composer program (phar) itself. This means Composer’s autoloader is useless without the Composer program itself, and that can throw some PHP developers for a bit of a loop.

All in all, Composer’s classmap feature is a powerful one, and a popular choice when a project that started without Composer finally decides to take the plunge. The ability to point Composer at at a class directory and have it magically find all your classes for you is a huge time saver.

With both the include files and classmap autoloader types, Composer seems well armed to handle any autoloading situation. However, recent development in the larger PHP community have led Composer developers to implement full support for both the PSR-0 and PSR-4 autoloading standards. Composer’s implementation of these standards will be our topic next time, when we continue to explore Composer’s autoloader implementations.

Originally published January 26, 2015

Laravel, Composer, and the State of Autoloading

Like this article? Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

PHP, the language, leaves a lot to be desired when it comes to sharing and organizing your code in a project. This problem goes back to PHP’s roots, and the choice not to include a python or ruby like module system. Over the years the PHP core team has added features to the language that can help developers crete their own code management systems, but the language itself has remained neutral.

One of those systems is the autoloader, and today we’ll be starting a series talking about the state of PHP’s autoloader culture, Composer, the PSR standards, and everything a developer new to Laravel needs to know about all of them.

Autoloading Basics

The basic idea behind autoloading is

  1. A programmer instantiates an undefined class
  2. Before PHP dies with a fatal error, it automatically calls a user defined function/callback, passing the class name as a parameter
  3. This user defined function implements logic to automatically include or require the class definition
  4. After running the autoloader, PHP instantiates the class

When an autoloader works well, it means a PHP developer can just start instantiating the classes they need, and the system will automatically include or require them behind the scenes.

There’s two different ways a PHP developer can create an autoloader. The first is to define a special global function named __autoload

function __autoload($class_name)
{
    //logic to load a class definition here
}

As a systems developer, this creates a few problems. The primary one is you can only define a single __autoload function. This means it’s impossible for two systems developers to have custom autoloaders unless they collaborate and agree on a single __autoload function, and then synchronize versions of their frameworks. Because of this, __autoload isn’t often used outside of private, single project frameworks.

To solve this problem, PHP also offers the spl_register_autoloader function. This function allows you to register multiple PHP callbacks as autoloaders.

//using an anonymous function
spl_autoload_register(function($class_name){
    //login to load a class definition here
});

//using a global function
function myCustomAutoloadDunction()
{
    //login to load a class definition here    
}
spl_autoload_register('myCustomAutoloadDunction');

//using a static method on a class
class MyCustomAutoloader
{
    static public function myLoader($class_name)
    {
        //login to load a class definition here            
    }
}
spl_autoload_register(array('MyCustomAutoloader','myLoader'));    

//using an instance method on an object
class MyCustomAutoloader
{
    public function myLoader($class_name)
    {
    }
}
$object = new MyCustomAutoloader;
spl_autoload_register(array($object,'myLoader'));    

Then, when a program instantiates an undefined class, PHP will call each registered function until it finds a definition. This way code from multiple frameworks can coexist, each with their own autoloaders.

Autoloading Standards

While the ability to registered multiple autoloaders has helped move PHP along, this approach is not without its own problems. A poorly behaving autoloader can still create conflicts for the other autoloaders. For example, Magento 1’s Varien_Autoloader doesn’t check if its class files exist before calling include, which means an error message when the class file isn’t found. If you want to include a second autoloader with Magento 1, you need to jigger the autoloading order with spl_autoload_functions and spl_autoload_unregister, which is far from ideal.

In recent years the PHP Framework Interoperability Group (PHP FIG) have developed two autoloader standards — the idea being that framework developers all agree to use these standards, and autoloader conflicts become a thing of the past.

While framework developers have been slow to discard their old autoloaders, the PSR-0/PSR-4 effort is buoyed by the PHP Composer project. Composer automatically includes PSR-0 and PSR-4 implementations for any package. A framework developer might meow meow meow about using the PSR standards in their own framework, but if they want to tap into the power of Composer distribution it means the PSRs come along on the ride for free.

Laravel’s Autoloading

All of this means that autoloading culture is in a state of flux. When everything works, it’s fantastic. A developer just instantiates a class and they’re off to the races. However, framework developers are hesitant to simply drop their old autoloaders for fear of confusing their community of end-user-programmers, many of whom might not even know the autoloader exists.

This means most PHP frameworks, even if they use Composer, have a number of autoloaders defined. Laravel presents an almost perfect case study of this. A stock instance of Laravel 4.2 has four autoloaders defined. You can see this for yourself by using the spl_autoload_functions function, but we’ll save you the trouble. Laravel’s four autoloaders are

  • Illuminate\Foundation\AliasLoader::load
  • Composer\Autoload\ClassLoader::loadClass
  • Swift::autoload
  • Illuminate\Support\ClassLoader::load

Two autoloaders come from the Laravel framework itself, another is Composer’s standard autoloader, and the fourth is a legacy autoloader included by a PHP library from the dawn of autoloaders.

The remainder of this tutorial will examine the specific implementation of each of these autoloaders. Future articles in the series will cover how they’re added to the system, how they interact with each other, and the additional steps needed to take advantage of the special Composer autoloader.

Laravel Class Loader

The Illuminate\Support\ClassLoader::load method is Laravel’s main autoloader. Its implementation is relatively straight forward.

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php    
public static function load($class)
{        
    $class = static::normalizeClass($class);

    foreach (static::$directories as $directory)
    {
        if (file_exists($path = $directory.DIRECTORY_SEPARATOR.$class))
        {
            require_once $path;

            return true;
        }
    }

    return false;
}

The first line of the loader

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php 
$class = static::normalizeClass($class);  

will “normalize” the classname. In this context, normalize means turning the class name into a file path by replacing any backslash namespace separators with directory path separators (“/” on *nix systems), and adding .php to the end.

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php 
public static function normalizeClass($class)
{
    if ($class[0] == '\\') $class = substr($class, 1);

    return str_replace(array('\\', '_'), DIRECTORY_SEPARATOR, $class).'.php';
}

This means the autoloader will normalize a class name like Namespace\Some\Class into Namespace/Some/Class.php`.

Next, the class loader will run through a list of directories

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php 
foreach (static::$directories as $directory)
{
    //...            
}

and for each one try to load a class definition using the just normalized class name prepended with the directory name

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php 
if (file_exists($path = $directory.DIRECTORY_SEPARATOR.$class))
{
    require_once $path;

    return true;
}

You’re probably wondering how $dirctories is populated — if you take a look at the app/start/global.php file, you’ll see the following

#File: app/start/global.php
ClassLoader::addDirectories(array(

    app_path().'/commands',
    app_path().'/controllers',
    app_path().'/models',
    app_path().'/database/seeds',

));

If we take a look at the definition for addDirectories

#File: vendor/laravel/framework/src/Illuminate/Support/ClassLoader.php 
public static function addDirectories($directories)
{
    static::$directories = array_unique(array_merge(static::$directories, (array) $directories));
}

we can see this methods adds each directory path to the static::$directories array. This means that, by default, the Laravel autoloader will search for our example Namespace\Some\Class class in

/path/to/laravel/app/commands/Namespace/Some/Class.php
/path/to/laravel/app/controllers/Namespace/Some/Class.php
/path/to/laravel/models/Namespace/Some/Class.php
/path/to/laravel/database/seeds/Namespace/Some/Class.php

So that’s Laravel’s first autoloader, but what about the second one?

Laravel Alias Class Loader

Next up, we’re going to cover the Illuminate\Foundation\AliasLoader::load autoloader. This is not Laravel’s primary autoloader. In fact, we’ll learn it doesn’t load any class files at all.

Let’s look at its definition.

#File: vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php
public function load($alias)
{
    if (isset($this->aliases[$alias]))
    {
        return class_alias($this->aliases[$alias], $alias);
    }
}

This is a pretty simple method, but a method that doesn’t actually load class definitions. Instead, this autoloader looks for the class name in the aliases object property (populated by the aliases configuration in app/config/app.php), and if it finds one, uses the class_alias function to define the alias. This effectively creates a lazy loader for Laravel’s PHP class aliases — the alias is only defined if it’s used.

So, when a program sends a class name like Str to this autoloader, the autoloader finds the alias defined as Illuminate\Support\Str

#File: app/config/app.php
'Str' => 'Illuminate\Support\Str',

and then defines the alias

#File: vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php
return class_alias('Illuminate\Support\Str', 'Str');

If you’re curious, Laravel populates the $this->alias property in the AliasLoader constructor

#File: vendor/laravel/framework/src/Illuminate/Foundation/AliasLoader.php
public function __construct(array $aliases = array())
{
    $this->aliases = $aliases;
}

PHP calls this constructor when Laravel instantiates the AliasLoader object, which happens in the framework start.php file

#File: laravel/framework/src/Illuminate/Foundation/start.php
$config = $app['config']['app'];
//...
$aliases = $config['aliases'];    
AliasLoader::getInstance($aliases)->register();

PHP includes this framework start.php file from the bootstrap start.php file

#File: bootstrap/start.php
$framework = $app['path.base'].
                 '/vendor/laravel/framework/src';
//...    
require $framework.'/Illuminate/Foundation/start.php';

Finally, bringing us back to the top of the stack, PHP includes the bootstrap start.php file in the main index.php file.

#File: index.php
$app = require_once __DIR__.'/../bootstrap/start.php';

This early stage loading of the AliasLoader class will become important in future articles when we start to investigate how Laravel’s autoloaders interact with one another. There’s some subtle timing elements you’ll need to be aware of.

The Swift Autoloader

Laravel comes bundled with “a clean, simple API over the popular SwiftMailer library”. However, like many venerable and popular PHP projects, SwiftMailer predates the popularity of the modern PSR autoloading standards, and has its own Swift::autoload callback for autoloading.

Step one for any Laravel programmer is figuring out if Swift is a Laravel facade, class alias, or just a plain old global class. In other words, is Swift::autolaod part of that clean, simple API over the popular SwiftMailer library, or is it a class that’s part of the SwiftMailer library itself. Reflection can help us out here — try running the following in a Laravel bootstrapped environment (i.e. a route function or controller action)

$class = new ReflectionClass('Swift');
var_dump($class->getFilename());

You should get something like the following

string '/path/to/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php' 

If we open up this class file returned by getFilename()

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php
<?php    
//...
abstract class Swift
{
    //...
}

we see there’s no namespace declaration. The file contains only an abstract class named Swift. This means Swift is not an alias (and by inference, not a Laravel facade), and instead a plain old fashion global class. While a modern PHP developer may be put off by this, given the SwiftMailer library dates back to 2004, it’s not exactly surprising.

We’ll get to how Laravel ends up including this autoloader in a later article — for now let’s take a look at its implementation.

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    
class Swift
{
    //...
    public static function autoload($class)
    {
        // Don't interfere with other autoloaders
        if (0 !== strpos($class, 'Swift_')) {
            return;
        }

        $path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';

        if (!file_exists($path)) {
            return;
        }

        require $path;

        if (self::$inits && !self::$initialized) {
            self::$initialized = true;
            foreach (self::$inits as $init) {
                call_user_func($init);
            }
        }
    }
    //...
}

The first thing you’ll notice is this conditional

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    
// Don't interfere with other autoloaders
if (0 !== strpos($class, 'Swift_')) {
    return;
}

Here, the SwiftMailer autoloader examines the class name, if it doesn’t start with the string Swift_, the autoloader method returns early. Per the comments, this means the swift autoloader will ignore other class files and play nice with other autoloaders. This assumes, of course, those classes don’t also start with Swift_ — these were the horrors of a pre-namespace world.

Next, the autoloader does a pretty standard bit of classname to path manipulation

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    
$path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';

This turns a class name like Swift_Foo_Bar into Swift/Foo/Bar.php, and then prepends it with the directory path the abstract Swift class lives in. At the end of this you’d have

Then, the autoloader ensures the file exists

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    

if (!file_exists($path)) {
    return;
}

and if so, uses require to load the class definition

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    

require $path;

Up until now, this is a pretty standard pre-PSR autoloader. However, there’s one last bit of code to contend with

#File: vendor/swiftmailer/swiftmailer/lib/classes/Swift.php    

if (self::$inits && !self::$initialized) {
    self::$initialized = true;
    foreach (self::$inits as $init) {
        call_user_func($init);
    }
}

Here, the SwiftMailer developers couldn’t resist a little systems programming, and have hijacked the autoloader process to do some bootstraping of their framework (remember, it’s frameworks all the way down). If there are any callbacks defined in the static $inits array, the first time a program uses a SwiftMailer class the autoloader will call those callbacks.

Composer Autoloader

Finally, we’re going to take a brief look at the Composer autoloader, Composer\Autoload\ClassLoader::loadClass. You’ll find its definition here

#File: vendor/composer/ClassLoader.php
public function loadClass($class)
{
    if ($file = $this->findFile($class)) {
        includeFile($file);

        return true;
    }
}

This is a small, well abstracted function that uses the class name to find the class definition file with the findFile method

#File: vendor/composer/ClassLoader.php
if ($file = $this->findFile($class)) {
    //..
}

and then includes that file with the includeFile function

#File: vendor/composer/ClassLoader.php
includeFile($file);

If you’re a new, or even intermediate programmer, you may be a little confused by the equality assignment in the conditional (note the single = for assignment, not comparison).

#File: vendor/composer/ClassLoader.php
if ($file = $this->findFile($class)) {
    //...
}

This line could be written more verbosely as

#File: vendor/composer/ClassLoader.php    
$file = $this->findFile($class);
if($file)
{
    //...    
}

Some programmers like this style because it reduces the number of code lines by 1. Other programmers don’t like it because they’ve addad a hard coded test in their brain that says “assignment in a conditional is a typo-bug”. We’ll leave that argument for the ages because we still need to look at the definitions of findFile and includeFile.

We’ll start with the simpler of the two — includeFile. You’ll find this function definition in the same file as the Composer classLoader

#File: vendor/composer/ClassLoader.php
function includeFile($file)
{
    include $file;
}

Your knee jerk response may be to question creating a new, globally scoped function with a single line to include a file. However, if you read this function’s comments

#File: vendor/composer/ClassLoader.php
/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 */
function includeFile($file)
{
    include $file;
}

you’ll see the Composer autoloader developers did this deliberately to avoid calling include from a class method. When you call include or require inside a method or function, the included PHP file inherits the function or class-method scope. The Composer team wanted to make sure their autoloader introduced no additional scope into the class files, so they used a global function with no additional variables (except, of course, the $file variable). Some may think this is a premature optimization — others would call it smart preventative system engineering. I call it something you’ll want to be aware of if you’re poking around the guts of Composer’s autoloader.

That digression out of the way, let’s take a look at the definition of the findFile method, which does the bulk of the Composer autoloader’s work

#File: vendor/composer/ClassLoader.php
public function findFile($class)
{
    // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
    if ('\\' == $class[0]) {
        $class = substr($class, 1);
    }

    // class map lookup
    if (isset($this->classMap[$class])) {
        return $this->classMap[$class];
    }

    $file = $this->findFileWithExtension($class, '.php');

    // Search for Hack files if we are running on HHVM
    if ($file === null && defined('HHVM_VERSION')) {
        $file = $this->findFileWithExtension($class, '.hh');
    }

    if ($file === null) {
        // Remember that this class does not exist.
        return $this->classMap[$class] = false;
    }

    return $file;
}

The first code block

#File: vendor/composer/ClassLoader.php
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
    $class = substr($class, 1);
}

Is to handle an early PHP 5.3 bug where, in some circumstances, PHP would pass the autoloader a class with the global namespace separator prepended and in other cases would not. It’s the second behavior that’s the defined standard, so this block makes sure a class string of \All\The\Great\Classes is normalized to All\The\Greate\Classes

Next, Composer looks for the specified class in its classMap array — if found, the method will return the configured file path, and its job is done.

#File: vendor/composer/ClassLoader.php
// class map lookup
if (isset($this->classMap[$class])) {
    return $this->classMap[$class];
}

If we’re still around, Composer calls the findFileWithExtension function to generate a path name.

#File: vendor/composer/ClassLoader.php
$file = $this->findFileWithExtension($class, '.php');

We’re not going to cover the implementation of findFileWithExtension right now, except to say it implements both the PSR-0, and PSR-4 autoloading standards.

The next block is an interesting bit for folks on the bleeding edge of PHP development

#File: vendor/composer/ClassLoader.php
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
    $file = $this->findFileWithExtension($class, '.hh');
}

If findFileWithExtension didn’t find a .php file, and the autoloader determines we’re running Facebook’s “Hack” PHP runtime (i.e. there’s a defined HHVM_VERSION constant), the autoloader calls the findFileWithExtension function again, but this time searching files with a .hh extension.

Finally, if the class file wasn’t found, Composer makes note of it in the classMap array

#File: vendor/composer/ClassLoader.php
if ($file === null) {
    // Remember that this class does not exist.
    return $this->classMap[$class] = false;
}

This way, if the PHP calls the autoloader again with the same class (possible in a multi-autoloader environment), Composer’s autoloader will skip the work of looking for the file again.

Wrap Up

As we said, that’s a brief summation of Composer’s autoloader. Before we can get to how all four autoloaders interact with one another, we’ll need to jump another level down the rabbit hole and examine how Composer populates its classMap property, and what, exactly, it’s doing in the findFileWithExtension method. That will be our topic next time when we take a quick detour from Laravel with Complete Composer Autoloading.

Originally published January 12, 2015

Eloquent ORM Static Meta-Programming

So far in this series we’ve stayed pretty focused on core Laravel concepts and their underlying implementation. However, this week we’re going to go slightly farther afield and discuss some of the static method meta-programming used by Laravel’s “Eloquent” ORM.

What’s an ORM

ORM stands for Object Relational Mapper. In less fancy terms, ORMs are systems that hide the underlying storage technology for your application’s data, and present client-programmers with simpler objects to manipulate.

As a web developer, the most common ORM pattern you’ll see is ActiveRecord. Most frameworks that ship with an ORM use one that implements and/or is inspired by ActiveRecord, and Laravel’s Eloquent ORM is no exception.

This article isn’t a full ORM, ActiveRecord, or Eloquent tutorial. If you’re not familiar with the concepts you’ll probably be OK — just think of an ORM as that thing we do instead of writing raw SQL.

Eloquent Parts

First, here’s a lightning round primer on the trinity of objects that you’ll use most commonly with Eloquent.

First, there’s your standard model object. A model represents the data for a single object or item. All models in Laravel inherit from the Illuminate\Database\Eloquent\Model object. There’s also an Eloquent class_alias setup in a stock Laravel system

#File: app/config/app.php
'aliases' => array(
    //...
    'Eloquent'        => 'Illuminate\Database\Eloquent\Model',    

This allows users to use the global shortcut Eloquent when defining their models.

#File: app/models/SportsBallPlayer.php
class SportsBallPlayer extends Eloquent
{
}

This is another area where Laravel shields users from PHP’s underlying namespace system.

To fetch models, Laravel has a query builder object (class name: Illuminate\Database\Query\Builder). You use a query builder object to fetch specific models from your system. In pseudo-code that might look like this

//pseduo code to simplify things, we'll explain more below
$player = new SportsBallPlayer;
$query_builder = new \Illuminate\Database\Query\Builder;
$query_builder->setModel($player);
$results = $query_builder
    ->where('height_in_inches','>','72')
    ->get();

You’re probably wondering what’s in the $results variable above. That brings us to the third, and final Laravel ORM object we’ll talk about today: The collection object (class name: Illuminate\Database\Eloquent\Collection). The collection object is an array-like PHP object that contains a collection of models returned by the query builder. The most common way you’ll use this object is via a for each statement

foreach($results as $model)
{
    var_dump($model->toArray());
}

If you’re new to PHP you may be surprised that data structures other than the built-in array type can be for eached. While it’s beyond the scope of this article, this ability comes by way of the IteratorAggregate interface. Magento developers should be familiar with the concept, but take note that Laravel doesn’t have typed collections.

The __call and __callStatic Methods

With that quick primer out of the way, we’re set to explore Eloquent’s use of __callStatic. That is, using our model above, what happens if we say

SportsBallPlayer::callTheThing(...);

and the SportsBallPlayer class doesn’t have a static callTheThing method defined. If you’ve been following along, you’ll know we want to jump right to the base model class’s __callStatic method

#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
public static function __callStatic($method, $parameters)
{
    $instance = new static;

    return call_user_func_array(array($instance, $method), $parameters);
}

As __callStatic methods go, this is pretty simple. Remember, the static keyword, as used here, is how a static method can refer to its calling class. In our case, the following lines are equivalent

$instance = new static;
$instance = new SportsBallPlayer

This means calling an undefined static method on an Eloquent model will

  1. Instantiate a new instance of that model
  2. Pass the static call on as an instance method call

Put in code, that means this

SportsBallPlayer::all(...);

is equal to this

$model = new SportsBallPlayer;
$model->all(...);

That’s pretty simple, and a clever way to save developers from needing to instantiate a model when they want to work with it.

However, let’s go back to our original example

SportsBallPlayer::callTheThing(...);

//or

$model = new SportsBallPlayer;
$model->callTheThing(...);

There’s no instance method named callTheThing. As you’ve no doubt already guessed, Eloquent models have a __call method defined as well, which will catch calls to undefined methods

#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php    
public function __call($method, $parameters)
{
    if (in_array($method, array('increment', 'decrement')))
    {
        return call_user_func_array(array($this, $method), $parameters);
    }

    $query = $this->newQuery();

    return call_user_func_array(array($query, $method), $parameters);
}

We’re going to ignore that first conditional, and concentrate on the last two lines

#File: vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php    
$query = $this->newQuery();

return call_user_func_array(array($query, $method), $parameters);

When you call an undefined method on an Eloquent model, Laravel will pass that method call on to an automatically instantiated query builder object. The newQuery method above returns a prepared query builder object, ready to query for your model. So, in simplified terms, that means our example

SportsBallPlayer::callTheThing(...);

//or

$model = new SportsBallPlayer;
$model->callTheThing(...);

actually expands out into something like

$model = new SportsBallPlayer;
$query = new Illuminate\Database\Query\Builder;
$query->setModel($model);
$query->callTheThing(...);

We say “simplified” because the instantiation of a query builder object is a complicated thing. It’s beyond the scope of this article, but if you’re interested it’s worth tracing out exactly what the newQuery method does.

Why do this?

In our callTheThing example, the end result here is the same. Since the query builder object doesn’t have a callTheTing method defined, PHP dies with a fatal error. That said, let’s consider a more common example.

SportsBallPlayer::where('height_in_inches','>','72')

There’s no where method defined on an Eloquent model. Instead, by passing the undefined method calls onto the query builder object, Laravel provides an instant shortcut to querying for a specific type of object. Even better, most of the query builder methods return themselves, which means method chaining is possible

SportsBallPlayer::where('height_in_inches','>',72)
->where('that_coach','=','Quite a Character')
->where('scoredowns', '=', 10);

Through a clever bit of meta-programming, Laravel maintains separation between the model logic and the querying logic, while still offering a simplified format that any PHP programmer can get started with. I know some programmers chafe at the marketing angle in many of Laravel’s system names, but this really is an eloquent pattern compared to many other ORMs.

Tradeoffs

There are of course, tradeoffs. The first I want to talk about is the similarity between these static method calls and Laravel facade calls. Consider the following

Auth::isLoggedIn();

Is this calling isLoggedIn on an Auth facade? Or is there an Eloquent model named Auth with an isLoggedIn method? Or (not likely, but still possible), does the query builder object have an isLoggedIn method for some reason? I know it’s a common refrain in this series, but Eloquent’s use of the static method calling surface area to implement meta-programming features means code is less readable until you have some level of expertise in the system. It’s one more thing you need to check when you’re debugging someone else’s code.

There’s also some confusion that’s confined to Eloquent. Consider the following

$model_first = SportsBallPlayer::whereRaw('1=1')->first();
$model_first = SportsBallPlayer::all()->first();

These two calls look the same, don’t they? In the simple case, they are. However, consider this

$model_first = SportsBallPlayer::whereRaw('1=1')->first(['name']);
var_dump(
    $model_first->toArray()
);

$model_second = SportsBallPlayer::all()->first(['name']);
var_dump(
    $model_second->toArray()
);

Again, identical looking calls. The first works as expected, restricting the columns requested from the database

array (size=1)
  'name' => string 'Gibson' (length=6)

However, the second call ends up throwing an exception

Argument 1 passed to Illuminate\Support\Collection::first() must be an instance of Closure, array given, called in /path/to/laravel/app/routes.php on line 257 and defined …

What gives? If we apply what we’ve learned, we know Eloquent routes the call to whereRaw through a query builder object. The query builder object implements a return $this for method chaining

#File: framework/src/Illuminate/Database/Query/Builder.php    
public function whereRaw($sql, array $bindings = array(), $boolean = 'and')
{
    //...
    return $this;
}

Which means the call to first is also made on the query builder object

#File: framework/src/Illuminate/Database/Query/Builder.php   
public function first($columns = array('*'))
{
    $results = $this->take(1)->get($columns);

    return count($results) > 0 ? reset($results) : null;
}

If we consider the second call, it’d be easy to jump to the same conclusion

$model = SportsBallPlayer::all()->first();

However, Laravel does not route the call to all through a query builder object. Why not? Because an all method is actually defined on the base Eloquent model

#File: framework/src/Illuminate/Database/Eloquent/Model.php
public static function all($columns = array('*'))
{
    $instance = new static;

    return $instance->newQuery()->get($columns);
}

This means all returns a collection object, and it is the collection object’s first method that’s really called.

#File: framework/src/Illuminate/Support/Collection.php
public function first(Closure $callback = null, $default = null)
{
    if (is_null($callback))
    {
        return count($this->items) > 0 ? reset($this->items) : null;
    }
    else
    {
        return array_first($this->items, $callback, $default);
    }
}

The problem here is two fold — first, without intimate knowledge of the base classes it’s impossible to tell which methods are passed along to a query builder object, and which are not. The second aspect is both the collection object and the query builder object have identical method names. This can lead to a number of confusing scenarios when querying for Eloquent models, with your only solution being rote memorization or relying on third party extensions for your IDE’s auto-complete.

These are, of course, the perils of meta-programming. The Eloquent querying model is an improvement — but at the cost of some confusion and learning curve. We’ll have more to say about this next time in a our final wrap-up article for this series.

Originally published November 15, 2014