Dependency Management with Composer

php

What you’ll learn

  • How to manage dependencies on third-party vendor libraries using Composer
  • Loading, namespacing and autoloading dependency managed code using Composer’s built-in PSR-0 autoloader
  • Publishing your own libraries via Packagist

What is Dependency Management?

Web applications rarely contain code exclusively developed by a single person or a single team. It’s more likely that an application will contain a mixture of code written uniquely for the purpose at hand, as well as a collection of general purpose libraries from third-party vendors.

Although PHP has lagged behind other languages in terms of the amount and quality of open source code available, the development ecosystem is starting to change. Large scale use of open source frameworks, initiatives such as PSR and influences from other languages’ communities mean that PHP developers are starting to get access to tools and libraries that make mass scale open source collaboration a reality.

As a result, PHP developers are composing their applications out of smaller components, usually written by open source communities and freely available through channels such as code.google.com and GitHub.

This kind of componentisation implies that hard dependencies: the code that we write cannot run unless other code that we’re relying on is available. Because of these dependencies, we need to include them in our codebase somehow. This raises some tricky questions:

  • Do we include these files in our source control management repository, or do we exclude them?
  • Do we package these dependencies with our codebase when sharing it with other developers, or send them the core application code and give them instructions on how to load the dependencies?
  • How do we manage versioning? What happens when the vendor updates the library?
  • How do we prevent different libraries with similar naming conventions from conflicting with one another?
  • What happens when a library we depend on has external dependencies on other libraries we don’t have installed?
  • When we deploy to different environments (development, staging or production) how can we be confident that the correct versions of our dependencies are going to be available at run time?

Until recently, these have been very difficult problems for PHP developers, with no clear solution available.

Enter Composer

Composer is a dependency management tool created and maintained by Nils Adermann, Jordi Boggiano and an active community of developers. It is written entirely in PHP, and works on all major platforms (*nix, Mac, Windows).

It consists of two key components:

  • Composer CLI tool: provides a command-line interface for installing and updating library depedencies on a per-project basis.
  • Packagist: an online “registry” for PHP packages that can be retrieved by Composer. Unless you plan on publishing your own packages for other developers to use it’s unlikely you’ll ever encounter Packagist.

Composer works by enabling you to declare the dependencies of your application in a human-readable format. It uses this format to connect to Packagist, search for the requested libraries and then download them to your project’s folder. These packages have their own dependency declarations so Composer will know if it needs to download any additional packages to get them working.

Note: Composer is not a package manager – it doesn’t manage libraries in a global namespace (like PEAR). Instead it focuses on managing package dependencies for individual projects, making it a dependency manager.

Getting started

Installing

Installing Composer is quite trivial. Simply navigate to your project’s folder and execute the following command:

$ curl -s http://getcomposer.org/installer | php

This will downlod and install the Composer binary to the current folder. It’s stored in a .phar file, which is a PHP Archive. You can run Composer to make sure it’s working using the following syntax:

$ php composer.phar

You should be greeted with the following dialog:

   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 8ebf445
Usage:
  [options] command [arguments]
...

Installing Globally

The steps listed above will install the Composer binary locally, so you can only use it from within the current project. This is a useful approach if you have limited access to the server you’re working on, but it does mean you’ll need to download Composer for every project you’re working on.

You can also install Composer globally, which will enable you to use it from within any project folder, as if you’d downloaded it to that location.

To do this, after executing the statement above, execute the following:

$ sudo mv composer.phar /usr/local/bin/composer
$ chmod a+x /usr/local/bin/composer

You can now run it as such:

$ composer

Configuring Dependencies

A file called composer.json (the dependency manifest) at the root-level of your project is used to define your project’s dependencies. As you may have guessed from the extension, this configuration file is in JSON format, and the most basic syntax is as follows:

{
    "require": {
        "twig/twig": "1.8.*"
    }
}

This tells Composer that our project depends on the “twig/twig” library, and we need the latest point release in the “1.8” stream (ie: “1.8.9”).

Loading dependencies

When we’re happy that all the dependencies of our class have been defined in the JSON file, we can trigger Composer to download the listed packages using the following command:

$ php composer.phar install

This will cause new files and folders to be created:

  • composer.lock: lists the packages and the versions that are currently installed.
  • vendor/: all composer related files go in here.
  • vendor/.composer: internal composer files are stored here.
  • vendor/*/: each package is given its own folder under the vendor parent folder.

If you’re using source control management software such as Git or SVN (and you are… right?) you should add the following to the list of ignored files:

vendor/
composer.phar

A Note on composer.lock

composer.lock lists all of the packages and the current versions that are installed. You should commit this to your source control repository and bundle it with your releases. This means that when developers run $ php composer.phar install, the same versions of the packages as those defined in the lock file will be used.

You can update versions of the repositories used afterwards using the update action:

$ php composer.phar update

Autoloading

As a PHP developer, you’re probably accustomed to writing long sections of require_once declarations at the top of your .php files to ensure all the required dependencies for your scripts are included. This is archaic, and if you’ve used other programming languages with more sensible approaches to modularisation you’ll understand how unreasonable it is for a modern programming language to expect this.

That’s where the PHP Standards Resolution (PSR) group comes in. PSR is a collective of PHP developers from prominent frameworks and libraries that set “industry standard” recommendations for writing PHP applications. The first official recommendation released from the group is PSR-0, which deals with a “best practice” way of automatically including .php files based on namespaces (introduced in PHP 5.3).

Composer provides its own autoloader, which is a script that can automatically include the files required to use libraries managed with Composer. To use it, you just need to require the autoloader file from the vendor folder:

<?php
require_once __DIR__ . '/../vendor/.composer/autoload.php';

// assuming Silex is managed by Composer…
use Silex\Application as Application;
$app = new Application();

Standard use cases

Including a Library available from Packagist

As we saw above, including a library availble from the Packagist repository is trivial – we simply add it’s name to a require clause in the manifest:

{
    "require": {
        "twig/twig": "1.8.*"
    }
}

Creating a Composer.json for your Libraries

If we’ve written a library and we want to share it with other developers, we can submit it to Packagist. To do this, we need to include a composer.json file in the repository that defines the following fields:

{
    "name": "top-level-namespace/library-name",
    "type": "library",
    "description": "Include a description of the library in here",
    "keywords": ["related keyword", "another related keyword", "etc..."],
    "homepage": "http://www.github.com/your-username/repository-name",
    "license": "MIT",
    "authors": [
        {
            "name": "John Smith",
            "email": "john.smith@smithdomain.com",
            "homepage": "http://www.smithdomain.com/john/"
        }
    ],
    "require": {
        "php": ">=5.3.0",
        "twig/twig": "1.8.*"
    },
    "autoload": {
        "psr-0": { "TopLevelNamespace": "lib/" }
    }
}

Add this to your Git repository, then go ahead and submit to Packagist. For an example of what this might look like, check out the composer.json file for the Predis library.

Managing dependencies not configured for Composer

Occasionally you may need to include a library that isn’t available via Packagist. This is a common use case for closed-source applications that may have non-publically available libraries as dependencies. These are typically stored in private repositories on Github or on Git servers on the local (private) network.

We can still use Composer to pull these repositories in by specifying their details in custom “repository” entires in our dependency manifest. An example is provided below:

    /* etc… */
    "repositories": [
        {
            "type": "vcs",
            "url": "git://mydomain.com:some-user/some-repository.git"
        }
    ],

    /* etc… */
    "require": {
        "some-user/some-repository": "master"
    }

For more details, check out the VCS section of the official Composer documentation.

Wrapping up

Composer provides a heavily opinionated solution to a serious problem for PHP developers. Although it makes certain decisions on your behalf, the conventions are well thought-out and make sense for most situations.

There are only a handful of options for PHP developers to manage their dependencies, so it’s a pleasure to discover that Composer is not just the best of a bad group of tools – but actually a good solution.

Using dependency management will change the way you work with PHP, and once you’ve started to use it, you’ll wonder how you ever survived without it.

For more information, check out the following resources:

  • http://getcomposer.org/doc/
  • http://www.phptherightway.com/#dependency_management
  • https://packagist.org/
  • http://fabien.potencier.org/article/64/php-is-much-better-than-you-think

Want to find out more?

We've worked with businesses just like yours to execute successful web projects helping them to optimise operations, improve marketing, and sell more online with custom software solutions. Reach out and tell us about your project for a free no-commitment consultation.

Find out more