Discovering Composer for PHP Dependencies

This post has a follow-up: Using Composer within PhpStorm, which shows how to leverage Composer support within PhpStorm.

It used to be that managing project dependencies required locating and downloading appropriate libraries, frameworks, tools, etc. This was a manual and tedious process. It was helped by using tools which were provided through PEAR, but that is now an outdated delivery mechanism.

Other programming languages have long had dependency managers; Ruby has Bundler, Python has Pip, and NodeJS has npm. Recent years have seen the uptake of Composer to manage dependencies for PHP projects.

This discovery topic provides an overview of Composer, explaining the basics of what it is for and how to use it. Examples will be shown for using Composer from the command-line.

Introducing Composer

The Composer website provides a jumping-off point for getting started. It includes documentation, quick-start instructions, downloads, and a link to the source on GitHub. If the issues and commits are anything to go by, it’s a very active project. By requiring a package in a project, Composer downloads the specified package (or updates it if appropriate); a package’s dependencies, and any further dependencies thereof, are also automatically downloaded.

Composer is the tool for managing project-specific dependencies, or packages. The packages themselves are listed on Packagist. The homepage shows the simplicity of requiring dependency packages within a project; there’s also a sample of how to define a package that could be consumed through Composer and used as a dependency. Packages can be consumed this way even if they are not available on Packagist; it’s possible to create private package repositories instead of using a public venue such as Packagist.

Packagist homepage
Packagist homepage

The package’s dependencies, as well as information about the package itself, are contained within a composer.json file located at the package root. There is a related file in the picture also, composer.lock. These are similar, yet have different uses, and are described below. Despite the differing extensions, both files are written in the JSON format.

composer.json

Dependencies are declared in the following way:

{
    "require": {
        "vendor1/package1": "1.0.1",
        "vendor1/package2": "0.9",
        "vendor2/package1": "2.1",
    }
}

To declare that the current project makes up a consumable package, add the name and description fields to the top of the outer object, e.g.:

{
    "name": "vendor-name/package-name",
    "description": "A brief description of the current package",
    "require": {
        "vendor1/package1": "1.0.1",
        "vendor1/package2": "0.9",
        "vendor2/package1": "2.1",
    }
}

If there are no dependencies, the require block can be omitted.

Packagist has guidance for naming and versioning, as well as a list of the fields that can be included in composer.json. These fields include:

  • type
  • keywords
  • homepage
  • license
  • authors
  • require
  • autoload

composer.lock

In the same directory as composer.json, it is possible to have a sibling file, composer.lock. When Composer installs dependencies, it writes their names and corresponding version numbers to this file. The purpose of this file is to ensure than when the install command is run, only the exact dependency versions are downloaded, regardless of what is listed in composer.json. This helps to avoid inconsistencies that may arise from different developers using slightly different dependency versions – even minor version updates can bring surprising changes.

If composer.lock isn’t present, it will be created after composer.json is read and the dependencies are installed or updated. The result of this behaviour is that Composer will not download newer versions of a dependency if an older version is specified in composer.lock, unless the lock file is updated manually or the update command is used. In the latter case, Composer will retrieve the latest version that matches the version pattern specified in composer.json.

Ideally, both files – composer.json and composer.lock – are committed to the project’s source control so they stay with the project. Commit changes to these files as required. Don’t commit the dependencies themselves, since they may change from time to time via the update command; let Composer manage the downloading of dependencies. It’s worth using the version control systems’ ignore capability to prevent the dependency directory from being added to source control.

Installing Composer

Installing Composer, naturally, requires that PHP is already installed; if this isn’t the case, go do that now, I’ll wait. The Composer website provides installation instructions. Installing on Windows is quite straightforward: just download and run the installer, which will install Composer if it hasn’t been already, or update it if it has. Of course, instructions are also provided for installation on Unix-y systems such as Linux and OS X.

Composer installation
Composer installation
Composer installation options
Composer installation options

Verification of a successful install can be obtained by opening a command line window and running the following command:

composer -V

(That’s an uppercase V; a lowercase v produces a different result) The result should look something like below:

Composer version
Composer version

Using Composer from the Command Line

To start using Composer, it’s worth trying the command line interface to better understand the available commands and parameters. Navigate to an empty directory, say C:composer. To require a package, a command must be run in the form of:

composer require [package name]

Supposing that the Yii framework (first major version) was required. The Yii package listing on Packagist follows:

Yii on Packagist
Yii on Packagist

Note the red outline containing yiisoft/yii. That is the package name to provide composer require. It is in the form of vendor/package – the whole string is required, not just the vendor or the package. This allows one vendor to have multiple different packages, and different vendors to have packages with the same name (for whatever reason).

According to the inline documentation, the require command:

Adds required packages to your composer.json and installs them

To install the latest version of Yii, with no pre-existing configuration, run:

composer require yiisoft/yii

A successful execution of the command generates the following output:

Composer CLI - require Yii
Composer CLI – require Yii

Running dir on the current directory reveals three new entries, outlined in red:

Composer CLI - post-Yii
Composer CLI – post-Yii

The entries are, respectively, composer.json, composer.lock, and vendor, which is a directory created to house required dependencies. Normally, all packages are located in the vendors folder, though it is possible to override the location for individual packages.

composer.json now has the following contents:

{
    "require": {
        "yiisoft/yii": "~1.1"
    }
}

composer.lock is surprisingly more extensive. Many of the details within are out of the scope of this introductory topic. Not to diminish them, but here is a simplified view of the file showing some particular details:

{
    "packages": [
        {
            "name": "yiisoft/yii",
            "version": "1.1.16",
            "source": {
                "type": "git",
                "url": "https://github.com/yiisoft/yii.git",
                "reference": "bca0420b6799b0b2a7966aa90bcd15cb4aa73563"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/yiisoft/yii/zipball/bca0420b6799b0b2a7966aa90bcd15cb4aa73563",
                "reference": "bca0420b6799b0b2a7966aa90bcd15cb4aa73563",
                "shasum": ""
            },
            "require": {
                "php": ">=5.1.0"
            },
            "bin": [
                "framework/yiic"
            ],
            "type": "library",
            "description": "Yii Web Programming Framework",
            "homepage": "http://www.yiiframework.com/",
            "keywords": [
                "framework",
                "yii"
            ],
            "time": "2014-12-21 19:30:17"
        }
    ],
    "minimum-stability": "stable",
} 

Now suppose that there is some issue (made up for the sake of this example) that renders Yii 1.1.16 unusable. It can be switched for the previous version, 1.1.15, with the following command:

composer require yiisoft/yii:1.1.15

In this example, Yii is being rolled back to a previous version. This command can also be used to install a specific version (not necessarily the latest) from the start. The above command generates the following output:

Composer CLI - post-Yii-rollback
Composer CLI – post-Yii-rollback

The composer.json and composer.lock files were updated accordingly.

It’s possible to write composer.json manually, then use that to download the packages and write the composer.lock file, but it may be less tedious to use composer require to do the bulk of the work. It’s now possible to drop a copy of the composer.json file into an empty directory, run composer install, and watch the packages come in.

Update
I created a repository which contains the files described in this post. They are deliberately simple, but do show how a dependency is required through Composer.

Conclusion

Manually managing dependencies is a drag. Other languages have had their respective package managers for quite some time; PHP’s entry to the club via Composer is relatively recent. Composer is straightforward to install, but really using it requires learning the setup of the configuration files – composer.json and composer.lock. Once those are set up, adding, updating, or removing dependencies is a straightforward process. What’s more, when the aforementioned files are kept as part of the project in version control e.g. Mercurial, getting up and running on a computer just requires PHP and Composer to be installed, a command to be run on a fresh checkout, and all dependencies will be downloaded. This way, dependencies, and versions thereof, are kept specific to the project and can be easily updated.

There are two general ways to use Composer:

  • create a package for possible use elsewhere
  • manage dependencies for the current project

It’s even possible to take both approaches within one project: create a project, which has its own dependencies, that can be packaged for reuse.

There are some related topics that didn’t get mentioned at all, or were touched upon briefly. Understanding of these would further improve usage, but weren’t essential for this introductory piece. They may be covered in follow-up posts, but for now they are left as an exercise for the reader.

  • version number patterns
  • separating out developer dependencies
  • custom installation locations
  • suggested dependencies
  • autoloading
  • custom repositories

The types of projects that can be supported by using Composer are diverse. It can be used to package a library or framework, or to manage dependencies for a website or web application or other end product. People have been using Composer to use WordPress and plugins as dependencies for a website (see the Roots project for an example), and to package themes and plugins. There has been some ongoing discussion about making WordPress core Composer-friendly.

Composer may seem like a simple tool, but the time that it saves and the structure it provides are huge benefits.