PHP package management history
20 Jan 18 20:00
4 minutes read

Reading the great article Modern Javascript Explained For Dinosaurs made me thinking on how that would look like if we were to look at PHP’s history of package management and autoloading.

A long time ago in a galaxy far, far away PHP 5 was released. It had numerous improvements compared with PHP 4 (while keeping backwards compatibility) but was still lacking a proper method of including/loading packages from other files.

The standard method for loading other files in php was to include or require the file. Frameworks, CMS’s and any other platform were doing manual includes of packages that made it relatively messy. Here’s a short snippet from phpBB 3.0 (~2008-12-13).

<?php
// Include files
require($phpbb_root_path . 'includes/acm/acm_' . $acm_type . '.' . $phpEx);
require($phpbb_root_path . 'includes/cache.' . $phpEx);
require($phpbb_root_path . 'includes/template.' . $phpEx);
require($phpbb_root_path . 'includes/session.' . $phpEx);
require($phpbb_root_path . 'includes/auth.' . $phpEx);
require($phpbb_root_path . 'includes/functions.' . $phpEx);
require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
require($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);

When PHP 5.1 appeared it introduced spl_autoload_register that enabled a way for defining rules for file loading. This simplified the above situation a lot, and improved maintainability.

Here’s a small snippet from Kohana 3.0 (~2011-02-10)

<?php
/**
 * Enable the Kohana auto-loader.
 *
 * @see  http://kohanaframework.org/guide/using.autoloading
 * @see  http://php.net/spl_autoload_register
 */
spl_autoload_register(array('Kohana', 'auto_load'));
...
try
{
    // Transform the class name into a path
    $file = str_replace('_', '/', strtolower($class));
    if ($path = Kohana::find_file('classes', $file))
    {
        // Load the class file
        require $path;
        // Class has been found
        return TRUE;
    }
    // Class is not in the filesystem
    return FALSE;
}
catch (Exception $e)
{
    Kohana::exception_handler($e);
    die;
}

Mind you we still had some problems.

  1. There is no formal definition on how to name files and folders to take advantage of the autoload for everybody.
  2. There was no package manager that would streamline package installation.
  3. PHP at the time didn’t had namespaces setting up imports from other packages could easily give name conflict issues (PHP 5.3 introduced namespaces).

Package naming

In order to solve the package naming issue, one of the first community created package naming is PEAR coding standard later followed by the ZEND coding standard

The explanation is pretty simple: Class names may only contain alphanumeric characters. Numbers are permitted in class names but are discouraged in most cases. Underscores are only permitted in place of the path separator; the filename Zend/Db/Table.php must map to the class name Zend_Db_Table.

Since then, with the release of PHP 5.3 and namespaces things advanced under the community leadership of the PHP working group (now called PHP-FIG).

The initial standard was PSR-0 (now deprecated). It allowed backwards compatibility with the PEAR/ZEND standard specifying that each _ character is converted into a DIRECTORY_SEPARATOR.

Here are some examples:

    \Symfony\Core\Request => /path/to/project/lib/vendor/Symfony/Core/Request.php
    \Zend\Acl             => /path/to/project/lib/vendor/Zend/Acl.php
    \Zend\Mail\Message    => /path/to/project/lib/vendor/Zend/Mail/Message.php

The latest autoloading standard from the community is PSR-4. It simplifies the rules in order to reduce the /really/long/paths/that/need/to/be/respected situations. This also removes the rule of having the _ as a DIRECTORY_SEPARATOR allowing for more natural naming of files.

Fully Qualified Class Name Namespace Prefix Base Directory Resulting File Path
\Acme\Log\Writer\File_Writer Acme\Log\Writer /acme-log-writer/lib/ /acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php

Package management

Regarding package management PEAR was released in 2003. Imho PEAR’s main goal was of installing system packages and global libraries and it was less suited for installing local application packages. Unfortunately it didn’t gain a lot of traction with PHP frameworks and CMS’s and it’s still mostly used for handling global packages and extensions.

Composer was born in 2011 as a more modern alternative to PEAR focused on applications. It built on the community acceptance of PSR-0 as an autoloader standard, and promoted a nicer and smarter way of handling application dependencies. Packages can also be easily searched on https://packagist.org/ and most of the PHP community rallied behind it. This, along with the PHP FIG standards, lowered the duplication work between projects.

That being said, PHP has grown a lot in the recent years thanks to the hard work of the community. Initiatives like PHP-FIG, Composer and the release of PHP 7 makes it a lot easier for new people to write maintainable PHP code, and hopefully reduce the stigma of PHP. I recommend reading PHP The Right Way to anybody that didn’t come in touch with modern PHP.

« Back to posts