Autoloading For Code Organization

composer autoload

Autoloading helps us to organize our code in a clean fashion. This makes it easier to understand how all of the pieces fit together. In fact, I would go as far as to say that code organization is half the battle. With the introduction of Composer to the PHP community, we now have a way to handle code organization like never before. As we know, Composer is The Dependency Manager for PHP. In addition to dependency management, Composer also provides efficient autoloading for us. We’ll explore autoloading in this tutorial now.


In our dependency injection for beginners tutorial, we built up a suite of classes to help us win the FIFA Soccer world championship. We had a Country, some Players, a Team, and many supporting methods and properties to accomplish our goal. We actually constructed our little application in a very top-down procedural style. That is to say, we had one big PHP file that kind of looked like this.

  • Class 1
  • Class 2
  • Class 3
  • Client code / Implementation of classes.

This is perfect for learning and tutorial-style applications. We can very quickly view everything that is happening in one simple PHP file. If you would like to build a larger application, however, this approach will begin to fail pretty quickly. Maybe you have ten or fifteen classes to account for, and many lines of code in your client to implement. One PHP file is not going to cut it in this case. The convention is actually to create one class per PHP file. From there, your client can either include the needed classes or autoload them for use. Let’s try to break our prior application into a proper organization with autoloading.


The /root directory

We can start with the root directory. In this directory, we will have our client code in the index.php file, in addition to a source directory which holds our classes. Inside the source directory are the following three files.

/root/source/Country.php

<?php

class Country
{
    protected $team;
    protected $name;
    
    public function __construct(Team $team, $name = 'USA')
    {
        $this->team = $team;
        $this->name = $name;
    }
    
    public function recruit(Player $player)
    {
        $this->team->join($player);
    }
    
}

/root/source/Player.php

<?php

class Player 
{
    protected $name;
    
    public function __construct($name)
    {
        $this->name = $name;
    }
}

/root/source/Team.php

<?php

class Team
{
    protected $players = [];
    
    public function __construct($players = [])
    {
        $this->players = $players;
    }
    
    public function join(Player $player)
    {
        $this->players[] = $player;
    }
    
    public function getplayers()
    {
        return $this->players;
    } 
}

/root/index.php

In our root directory, we also have our client code which looks like this.

<?php

$team = new Team;

$usa = new Country($team);

$player1 = new Player('Carli Lloyd');

$usa->recruit($player1);

$player2 = new Player('Morgan Brian');
$player3 = new Player('Ashlyn Harris');
$player4 = new Player('Tobin Heath');
$player5 = new Player('Alex Morgan');

$usa->recruit($player2);
$usa->recruit($player3);
$usa->recruit($player4);
$usa->recruit($player5);


echo '<pre>';
print_r($team->getplayers());

When we try to run our program, things are not looking good!

Fatal error: Class ‘Team’ not found in C:\wamp\www\root\index.php on line 3

include the Needed Class Files

You might be thinking, well that is an easy fix. We just need to include the needed class files like so.

include('source/Country.php');
include('source/Player.php');
include('source/Team.php');

$team = new Team;

$usa = new Country($team);

$player1 = new Player('Carli Lloyd');

$usa->recruit($player1);

$player2 = new Player('Morgan Brian');
$player3 = new Player('Ashlyn Harris');
$player4 = new Player('Tobin Heath');
$player5 = new Player('Alex Morgan');

$usa->recruit($player2);
$usa->recruit($player3);
$usa->recruit($player4);
$usa->recruit($player5);


echo '<pre>';
print_r($team->getplayers());

When we run this, everything does work just fine.

include class files

There is a better way, however, and that is to make use of autoloading with Composer. Manually including files is not going to scale, and will lead to trouble down the line. Let’s see how to fix this with Composer.


Autoload With Composer

From here on out, we’ll assume you already have Composer installed. If you don’t, go ahead and install now before proceeding. With Composer installed, we can navigate to our project root using the terminal. In our case that is C:\wamp\www\root> If you’ve never used Composer before, simply type composer to see what is available to us.

C:\wamp\www\root>composer
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.0-dev (39e6f51bef3a4b148d9f35a0ae7a082e9aed97f4) 2015-07-09 11:04:41

Usage:
 command [options] [arguments]

Options:
 --help (-h)           Display this help message
 --quiet (-q)          Do not output any message
 --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
 --version (-V)        Display this application version
 --ansi                Force ANSI output
 --no-ansi             Disable ANSI output
 --no-interaction (-n) Do not ask any interactive question
 --profile             Display timing and memory usage information
 --working-dir (-d)    If specified, use the given directory as working directory.

Available commands:
 about            Short information about Composer
 archive          Create an archive of this composer package
 browse           Opens the package's repository URL or homepage in your browser.
 clear-cache      Clears composer's internal package cache.
 clearcache       Clears composer's internal package cache.
 config           Set config options
 create-project   Create new project from a package into given directory.
 depends          Shows which packages depend on the given package
 diagnose         Diagnoses the system to identify common errors.
 dump-autoload    Dumps the autoloader
 dumpautoload     Dumps the autoloader
 global           Allows running commands in the global composer dir ($COMPOSER_HOME).
 help             Displays help for a command
 home             Opens the package's repository URL or homepage in your browser.
 info             Show information about packages
 init             Creates a basic composer.json file in current directory.
 install          Installs the project dependencies from the composer.lock file if present, or falls back on the composer.json.
 licenses         Show information about licenses of dependencies
 list             Lists commands
 remove           Removes a package from the require or require-dev
 require          Adds required packages to your composer.json and installs them
 run-script       Run the scripts defined in composer.json.
 search           Search for packages
 self-update      Updates composer.phar to the latest version.
 selfupdate       Updates composer.phar to the latest version.
 show             Show information about packages
 status           Show a list of locally modified packages
 suggests         Show package suggestions
 update           Updates your dependencies to the latest version according to composer.json, and updates the composer.lock file.
 validate         Validates a composer.json

We need a composer.json before anything else, so that init command looks good to us. This command will take you through the process of creating a project using a composer.json file. For the purposes of this tutorial, it will create a lot you don’t need, so once you have your composer.json, simply edit it so you only have an empty file containing the { and } characters, then run composer install which will generate the autoload.php file we need. In fact, a few things are now created in our project, let’s see.


/root

Note we now have a vendor directory in our root.
root directory

 


/root/vendor

As well as a newly created autoload.php file
autoload file

 


/root/vendor/composer

And finally, some various supporting files for Composer.
root vendor composer directory

 


Behold! The Autoload File!

<?php

// autoload.php @generated by Composer

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

return ComposerAutoloaderInit8ba53b7977ed0d2d530d1c0d7714ddcf::getLoader();

Configure PSR4

We’re almost there. First, we need to configure the composer.json file for PSR4 autoloading.

{
    "autoload": {
		"psr-4": {
			"Myapp\\": "source"
		}
	}
}

Once you declare your namespace, you’ll need to run composer dump-autoload in order to generate the proper autoloading files. Let’s see.

autoload_psr4.php

<?php

// autoload_psr4.php @generated by Composer

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

return array(
    'Myapp\\' => array($baseDir . '/source'),
);

Include the Autoloader

Recall that the index.php file lives in the root of our project. Note that in a prior step, we simply used three include statements to make use of the three classes we need to run our application. At this point, we are no longer using multiple include statements, but we will need to include the autoloader file just one time in our client code so that it will automatically load any class we need. In addition, we will add use statements for the Team, Country, and Player classes. We can update our client code like so.

<?php

require('vendor/autoload.php');

use Myapp\Team;
use Myapp\Country;
use Myapp\Player;

$team = new Team;

$usa = new Country($team);

$player1 = new Player('Carli Lloyd');

$usa->recruit($player1);

$player2 = new Player('Morgan Brian');
$player3 = new Player('Ashlyn Harris');
$player4 = new Player('Tobin Heath');
$player5 = new Player('Alex Morgan');

$usa->recruit($player2);
$usa->recruit($player3);
$usa->recruit($player4);
$usa->recruit($player5);


echo '<pre>';
print_r($team->getplayers());

This is perfect, but when we try to run our application, we get an error of: Fatal error: Class ‘Myapp\Team’ not found in C:\wamp\www\root\index.php on line 9. This is because we had set a namespace for Myapp. If we declare a namespace via PSR4, we need to make sure to update our class files to make use of those namespaces.

Update Class Namespaces

This is super easy. All we have to do is add namespace Myapp; to the top of our Class files.

/root/source/Country.php

<?php

namespace Myapp;

class Country
{
    protected $team;
    protected $name;
    
    public function __construct(Team $team, $name = 'USA')
    {
        $this->team = $team;
        $this->name = $name;
    }
    
    public function recruit(Player $player)
    {
        $this->team->join($player);
    }
    
}

/root/source/Player.php

<?php

namespace Myapp;

class Player 
{
    protected $name;
    
    public function __construct($name)
    {
        $this->name = $name;
    }
}

/root/source/Team.php

<?php

namespace Myapp;

class Team
{
    protected $players = [];
    
    public function __construct($players = [])
    {
        $this->players = $players;
    }
    
    public function join(Player $player)
    {
        $this->players[] = $player;
    }
    
    public function getplayers()
    {
        return $this->players;
    } 
}

Now, when we run the client code, we are right back to our championship-winning ways.
include class files

Composer Autoloading Summary

Composer is the best thing in the world for PHP developers. In this tutorial, we took a look at just one aspect of what makes Composer so great, and that is its ability to generate robust autoloading components for your application. With this newfound skill, you can better organize and scale your applications no matter how many class dependencies they might have.