18 Mar 2015 · Software Engineering

    Getting Started with Composer for PHP Dependency Management

    12 min read
    Contents

    Introduction

    Dependencies are essential for modern development. They save you time and energy. Functionalities you may need for your app like sending e-mails or logging can all be easily included as third party libraries. Thanks to the open source movement, there are many high quality packages to choose from. In the early days, including third-party libraries was cumbersome and error prone but luckily, today we have tools like Composer to help us.

    Composer is an exceptional dependency manager for PHP. It replaces PEAR and rightfully so. PEAR requires that your project is specially prepared to work with it, where Composer gives you all the freedom you need without any special requirements. One major difference between these two tools is that PEAR installs dependencies globally and Composer installs them locally, in your project structure. PEAR is essentially a package manager and Composer is a dependency manager. That’s where the emphasis is.

    Composer was inspired by projects like NPM and Bundler. The vast selection of compatible packages are hosted on the official Composer repository called Packagist. These packages are open source so you can contribute to them too. Popular frameworks and tools like Laravel, PHPUnit and Monolog can all be found here. You can even use a specific code revision of the package when including it in your project so you are getting great flexibility. Composer packages are versioned, so you can pin down the exact version of the package you need. This makes porting your project to another machine or to a CI service such as [Semaphore] (https://semaphoreci.com) effortless.

    In this tutorial, we’ll explore some of the most used Composer features and show how to use them. After following through, you should be comfortable with managing your PHP project’s dependencies with Composer.

    Prerequisites

    The software you need is as follows:

    • Some version of PHP 5, preferably the latest. Composer is compatible with PHP versions 5.3.2 and up.
    • Clients for Git and Subversion

    I’ll be using PHP version 5.6.5, but it’s perfectly fine to use any other version you have as long as it’s newer than 5.3.2. If you don’t have PHP installed, you can do it with phpbrew which makes managing multiple PHP versions on the same machine easy.

    Installation

    Composer can be installed in two different ways.

    Install Locally

    Local installation will download composer.phar to the current directory. The drawback of this method is that you’ll always have to reference the Composer’s executable from the directory where it’s downloaded to.

    $ curl -sS https://getcomposer.org/installer | php
    
    All settings correct for using Composer
    Downloading...
    
    Composer successfully installed to: /workspace/composer.phar
    Use it: php composer.phar
    
    $ php composer.phar --version
    
    Composer version 1.0-dev (1d8f05f1dd0e390f253f79ea86cd505178360019)

    Installing Composer globally is a handy way to have access to the tool from anywhere by just executing the composer command.

    $ curl -sS https://getcomposer.org/installer | php
    
    All settings correct for using Composer
    Downloading...
    
    Composer successfully installed to: /workspace/composer.phar
    Use it: php composer.phar
    
    $ sudo mv composer.phar /usr/local/bin/composer
    $ composer --version
    
    Composer version 1.0-dev (1d8f05f1dd0e390f253f79ea86cd505178360019)

    If you installed PHP with phpbrew running the command below is sufficient

    phpbrew install-composer

    We continue this tutorial with the assumption that Composer has been installed globally.

    Configuring Composer

    Composer is configured with a single file named composer.json located in the root directory of the project. To follow along, just create an empty directory called composer-tutorial, fire up a text editor and create an empty composer.json file in this directory. Here’s how the most simple Composer file looks like:

    {
      "require": {
        "symfony/yaml": "2.6.4"
      }
    }

    The only requirement other than the fact that the file has to be in a JSON format, is the inclusion of the require key. This key defines your project’s dependencies with a list of packages and their respective versions.

    Defining Dependencies

    By convention, package names consist of the package’s vendor and its project name. This is done in an effort to avoid name conflicts. In our example above, the vendor is symfony and the project is called yaml.

    The version of the package can be defined in multiple ways. This is where Composer gives you huge flexibility.

    • 2.6.4, locks the package to the exact version defined
    • >= 2.6.4, defines a range where the package’s version has to be at least 2.6.4 but a newer version is used if it’s available. Operators like <, <=, >, >= and != can also be used.
    • 2.6.*, which is equivalent to >=2.6 <2.7.
    • ~2.6, is used for projects which use semantic versioning and is equivalent to >=2.6 <3.0. It essentially allows the micro version to change: ~2.6.4 is the same as saying >=2.6.4 <2.7.0.
    • ^2.6, caret is used when we want to avoid braking updates for projects which employ semantic versioning. ^2.6 is equivalent to >=2.6.4 <3.0.0.

    A more detailed description of these restrictions can be found on [this page] (https://getcomposer.org/doc/01-basic-usage.md#package-versions).

    Breaking Out of the Defaults

    If you’re not satisfied with the default settings, you can use the config key and customize anything from specifying Composer’s default installation path to defining GitHub protocols to use. For example, to define a custom installation path for our Composer packages, we alter our composer.json to look like this:

    {
      "config": {
        "vendor-dir": "dependencies"
      },
      "require": {
        "symfony/yaml": "2.6.4"
      }
    }

    A full list of config options can be found here.

    Custom package sources

    A package is essentially a directory containing information like the version of the package and the source from where to get the contents of the package. Two types of package sources exist:

    • dist, a packaged version, tested and stable
    • source, clones the contents of the package from a version control system

    Packages from source are usually used in development and dist packages tend to be production ready.

    Composer by default uses dist packages from Packagist. However, this can be easily expanded by using the repositories key and including source packages. You can use sources like version control systems (Git, SVN and Hg) or even PEAR packages. To add the monolog library directly from GitHub, the following has to be done:

    {
      "repositories": [
        {
          "type": "vcs",
          "url": "https://github.com/Seldaek/monolog"
        }
      ],
      "require": {
        "symfony/yaml": "2.6.4",
        "monolog/monolog": "1.12.0"
      }
    }

    Repositories are a list of versions for the package. We require a version from the repository the same way we do with dist packages.

    Refer to this page for an in-depth explanation of the various options for configuring repositories.

    Installing dependencies

    To install the dependencies you defined in composer.json, we use the following command:

    composer install

    The installation process will fetch the latest packages according to the constraints we defined. The packages are put in the vendor directory or to a custom directory like we defined earlier. The installation command has a couple of interesting options.

    • --prefer-source will install the packages from their source which is usually a GitHub or a Subversion repository. In other words, it clones the package’s source. In the case where the repository is not found on the vcs, it falls back to the installation from dist.
    • --prefer-dist prefers to install packages from Packagist and caches the package archives locally.
    • --profile will give you statistics about the installation at the end of the process. It can be used with any Composer command.

    Caching dependencies

    Composer stores its cache in $COMPOSER_HOME/cache which is usually set to ~/.composer/cache by default. Caching is very beneficial when there are multiple projects which have some dependencies in common. The first time composer install is executed, it downloads and caches the dependencies which are not present in the cache. The next time it’s initiated, it’ll load the installed packages from cache.

    Let’s see what difference does the installation from cache can make.

    user@host:~/workspace/project-1/$ composer install --prefer-dist --profile
    [6.5MB/0.03s] Loading composer repositories with package information
    [6.8MB/0.48s] Installing dependencies (including require-dev)
    [47.0MB/12.45s] - Installing symfony/yaml (v2.6.4)
    [47.1MB/13.70s] Downloading: 0%[47.1MB/13.71s]
    ...
    [47.1MB/13.93s] Downloading: 100%[47.1MB/13.93s]
    [46.8MB/14.37s] Writing lock file
    [46.8MB/14.37s] Generating autoload files
    [46.8MB/14.37s] Memory usage: 46.77MB (peak: 56.15MB), time: 14.37s

    Here’s what happens when a cached packaged is reused for another installation:

    user@host:~/workspace/project-2/$ composer install --prefer-dist --profile
    [6.1MB/0.03s] Loading composer repositories with package information
    [6.4MB/0.41s] Installing dependencies (including require-dev)
    [46.5MB/3.65s] - Installing symfony/yaml (v2.6.4)
    [46.9MB/3.65s] Loading from cache
    [47.0MB/3.68s]
    [46.6MB/4.07s] Writing lock file
    [46.6MB/4.07s] Generating autoload files
    [46.6MB/4.07s] Memory usage: 46.62MB (peak: 55.65MB), time: 4.07s

    As you can see, installing cached packages is much faster the second time. This makes a big difference in a project with many dependencies.

    Locking down dependencies

    When the installation process is initiated the first time, it creates a composer.lock file. This file locks down all the currently installed packages with their versions and dependencies. It’s important to include this file to the version control system, because this is what makes your project transferable to other machines. This way you can rest assured that anyone who contributes to the project will have the same dependencies installed as you.

    Updating dependencies

    Frameworks and libraries are being improved all the time and if we want to get the latest features and bugfixes, our dependencies need to be kept up to date. This can be achieved simply by using the update command.

    composer update

    The update command will install all the latest packages while taking into consideration the version constraints defined in composer.json and it also updates the composer.lock file.

    Updating all the dependencies however isn’t always optimal. Maybe there’s a breaking change in one of the updates and you want to keep the old version until you handle it later. Composer packages can be updated one-by-one by letting the update command which vendor/project you want updated.

    composer update symfony/yaml

    The update command has very similar options to install and they can be found here.

    During your time with installing and updating Composer packages, you might meet this error message:

    Warning: The lock file is not up to date with the latest changes in
    composer.json, you may be getting outdated dependencies, run update to update
    them.

    This happens when even a tiniest adjustment is introduced in composer.json. Like changing the author, description or even altering a single letter. The slightest modification is enough to change the file’s MD5 hash which is detected by composer.lock. To avoid running the update when a trivial modification occurs, the --lock option is used to suppress the warning and update the lock file.

    composer update --lock

    Autoloading

    You may have noticed that Composer is generating autoload files after the packages are successfully installed or updated. More specifically, the file in question is vendor/autoload.php. Autoloading makes it really convenient to use the available dependencies throughout your project by simply referencing their class names without the need to explicitly require the files where the classes reside. The only thing that needs to be included in your project is the autoload file.

    Composer currently supports these autoloading mechanisms:

    • PSR-0
    • PSR-4 (recommended)
    • Class map generation
    • Directly referencing a file

    There’s even an option to autoload your own classes which we will demonstrate next.

    Autoloading a custom class

    Let’s see a simple example about how autoloading works. In our root directory composer-tutorial, create a directory called source. In this newly created directory, create a file called Square.php.

    <?php
    namespace Shapes;
    
      class Square {
        static function area($side){
          $surface_area = $side * $side;
    
          echo "The squares surface area is $surface_area units\n";
        }
      }

    The area function calculates the square’s surface area according to its side.

    Add the autoload key to composer.json where we define the mapping between the namespace and the path. Composer will look for files located in ./source which belongs to the /Shapes namespace.

    // composer.json
    {
      "autoload": {
        "psr-4": {"Shapes\\": "source/"}
      },
      "repositories": [
        {
          "type": "vcs",
            "url": "https://github.com/Seldaek/monolog"
        }
      ],
      "require": {
        "symfony/yaml": "2.6.4"
      }
    }

    After the custom class is included the autoload file has to be regenerated to reflect the changes.

    composer dump-autoload

    You can see the effect of dump-autoload in vendor/composer/autoload_psr4.php.

    <?php
    
    // autoload_psr4.php @generated by Composer
    
    $vendorDir = dirname(dirname(__FILE__));
    $baseDir = dirname($vendorDir);
    
    return array(
        'Shapes\\' => array($baseDir . '/source'),'
    )

    Now, let’s create a simple command line script which will use the Square class by just requiring vendor/autoload.php and nothing more. Create this file in the root directory (composer-tutorial) and name it calculate_area.php.

    #! /usr/bin/env php
    
    <?php
    require_once __DIR__ . '/vendor/autoload.php';
    
      $side = isset($argv[1]) ? $argv[1] : null;
    
      if (isset($side) && ctype_digit($side)) {
        Shapes\Square::area($side);
      }
      else {
        echo "Please provide a valid size!\n";
      }

    After the file is created, make it executable and run it.

    $ chmod +x ./calculate_area.php
    $ ./calculate_area.php 40
    The square's surface area is 1600 units

    Our Shapes\Square class was successfully loaded without the need to explicitly include it.

    Wrapping it up

    In this tutorial we saw how Composer manages dependencies for PHP projects. This versatile tool is now part of many developers’ arsenal. I hope this article managed to bring you up to speed with Composer.

    For a detailed overview of the capabilities of the command line interface, refer to the Composer documentation.

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Avatar
    Writen by: