Contents


PHP renewed

Composer for PHP dependency handling

Assemble your PHP projects from third-party libraries with a powerful open source tool

Comments

Content series:

This content is part # of # in the series: PHP renewed

Stay tuned for additional content in this series.

This content is part of the series:PHP renewed

Stay tuned for additional content in this series.

As PHP has matured, applications built with it have grown drastically in complexity. Modern PHP developers often rely on third-party libraries to help them build their software projects more quickly. An application the size of Facebook, for example, couldn't be built without the use of the well-maintained third-party libraries now available for PHP. But the benefits of software reuse come with a cost: You must manage not only the list of libraries that each installation of your application needs, but also a tree of dependencies that's created because each library you use was built on top of others. How can you manage a complicated, interdependent arrangement of multiple libraries?

The two dependency-handling solutions that PHP developers commonly used in the past have outlived their effectiveness. One was to check any library you needed into your version-control repository alongside your own code. This technique worked to an extent but often caused more trouble than it solved. You needed to maintain your own local version of the library. And you had to manually implement any available bug fixes for the library by downloading the new version and checking it into your repository. You'd end up with a massive change log in your version control that had nothing to do with your actual code. For these reasons, libraries usually lingered at whatever version they happened to be checked in at inception, rarely getting updated.

The PHP Extension and Application Repository (PEAR) project was designed, in part, to help solve this concern. PEAR provides a set of libraries, which programmers can contribute to, that all work together. PEAR also includes command-line tools for installing the libraries that you want along with their dependencies (if any). For a long time, PEAR was the best approach and was used by many, but this system also has shortcomings.

PEAR library installations are stored globally on the operating system. Although this design obviates the need to check the libraries into your own version-control repository, it causes more problems than it solves. You never know exactly which library versions are running on any system you might use. This confusion often became the source of faux bugs: You'd install your application on a new server and then be stymied as to why it wasn't working, eventually realizing that the server in question didn't have the right PEAR libraries in place. And you needed access to install those global libraries (a problem that many people on shared hosting struggled with).

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you are as clever as you can be when you write it, how will you ever debug it?

Brian Kernighan

In April 2011, two PHP developers, Nils Adermann and Jordi Boggiano, decided that PHP needed a new solution to the dependency-handling problem and began working on one. They released Composer on March 1, 2012. In Composer you create a configuration file specifying the third-party libraries that your application needs (regardless of where they are hosted). Then you run Composer to compose your full application: Composer downloads all the libraries that you specified and all of their dependencies. This article goes through the basics of Composer and shows how you can start using the tool in your PHP projects.

Installing Composer

Composer is a multiplatform tool. Installation is straightforward on any UNIX®-based or Linux® computer. You can create a local installation by running the installer via curl and PHP directly:

curl -sS https://getcomposer.org/installer | php

The preceding command creates an installation of Composer into a local composer.phar executable file. To make this installation globally accessible anywhere on your system, copy composer.phar to a directory in your path, as in this example (you might need to use sudo to give yourself permission to write to the root directories):

mv composer.phar /usr/local/bin/composer

Now you can run composer from the command line anywhere on your system.

On Windows®, a manual installation is more difficult, so the Composer creators developed an installer that you can download and run. After installation, you can use Composer from the Windows command line.

Basic usage

Composer is a powerful tool with an amazing array of options. Most commonly, though, you'll use it to create/download/install a code base for third-party PHP applications or frameworks, based on a configuration that the third party supplies. For example, you can use Composer to install the Zend Framework and all of its dependencies. You run Composer with the install command, and Composer takes care of the rest.

If you installed Composer globally (or on Windows), run:

composer install

If you only did a local Composer installation for one application, run:

php composer.phar install

For the rest of this article, my examples assume that you installed Composer globally.

In addition to downloading all the libraries that your project/application needs, Composer also provides a way for you to include all of them easily. It installs all of the libraries into a folder named vendor to distinguish them from your own project's code. Inside the vendor folder, it creates a file called autoload.php. Inclusion of this file in your project sets up an autoloader for all the libraries that Composer downloaded for you:

require 'vendor/autoload.php';

How Composer finds libraries

To download library packages for you, Composer needs to know where to find these packages to begin with. This information is provided by Composer repositories: online sources that list packages that are available on the Internet, how they can be retrieved, and what their own dependencies are. Although anyone can maintain their own repository for providing access to internal libraries (and the Composer website provides instructions for doing so), the main repository that you'll use is Packagist. Packagist provides packages for the majority of open source projects in PHP. You can go there to find the libraries that you need.

Software libraries aren't often known for working well together. The glue that binds all of the Packagist libraries together is provided by the PHP Framework Interop Group (originally called the PHP Standards Group), which was created at the php[tek] 2009 conference. The PHP-FIG — a group of people who represent numerous popular PHP applications and frameworks — was formed to see how their projects could better work together. The culmination of this cooperation is the creation of PHP Standards Recommendations (PSRs), which describe optional standards for libraries. Libraries that implement these common standards are able to interoperate under a shared set of expectations.

The most important PSRs that facilitated the creation of Composer are PSR-0 and PSR-4. These PSRs declare a common naming method for classes and namespaces, and how they should map to files on the file system. In turn, a common autoloader interface can load classes from any library that it needs to. Creation of a common, standardized way for libraries to share their classes without overwriting one another has enabled Composer to be as effective as it is.

Configuring Composer for your own projects

Now that you know how to install Composer, understand how the auto-loading works, and can find packages that you want to use, I'll take you through an example of setting up Composer for your own project.

I'm going to begin writing a new PHP project — a small program that will convert Markdown files into HTML output. Searching on Packagist for markdown brings up the michaelf/php-markdown library as a good choice and shows me the URL for the project's home page, as shown in Figure 1:

Figure 1. Library entry on Packagist
Screenshot of the michelf/php-markdown listing on Packagist
Screenshot of the michelf/php-markdown listing on Packagist

To tell Composer which files to include in your project, you create a configuration file named composer.json. This JSON-formatted file can contain various commands, but the most common (and often only) command that you will need is the require key. To this key, I pass in the package name that I want and which versions I'll support:

{
   "require": {
      "michelf/php-markdown": "1.4.*"
   }
}

Now I can run composer install in my application directory. Composer takes a few minutes to download the library requirement that I specified into a vendor directory and creates an autoloader for me that includes this directory. Composer also creates another file, composer.lock, which I'll describe in more detail in a minute. The commands and output look something like this:

> ls
composer.json
> composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing michelf/php-markdown (1.4.1)
    Downloading: 100%         

Writing lock file
Generating autoload files
> ls -F
composer.json composer.lock vendor/

Now I can write code that relies on the michelf/php-markdown package. The following short PHP script will do what I want:

<?php
require 'vendor/autoload.php';

use \Michelf\Markdown;
echo Markdown::defaultTransform(file_get_contents("php://stdin"));

Thanks to Composer, I have a straightforward and simple solution. The Markdown package that I chose has no additional dependencies, as it happens. But if I'd chosen one that did, Composer would have automatically pulled in all of those dependencies at the same time and configured them.

Specifying versions

You can add in as many libraries as your software needs to the composer.json file, and with each one, you can specify a version that you want to accept. Specifying versions is an important part of ensuring that your software will always work. By using a wildcard in the version number, you can even allow Composer to upgrade libraries on your behalf. In the previous example, I specified the version as "1.4.*". Now whenever composer install is run, Composer will find the latest version of the 1.4 release of the library but will not accept 1.5, 2.0, or any other higher versions. I could have specified "*" if I wanted to always get the latest version of the library (though that could potentially cause issues if the underlying API were changed).

Table 1 shows a full list of options that you can use when specifying version constraints.

Table 1. Package version constraints
SpecificationExampleDescription
Exact version1.0.2The exact version of a package.
Range>=1.0>=1.0 <2.0>=1.0 <1.1 || >=1.2Comparison operators can specify ranges of valid versions. Valid operators are >, >=, <, <=, !=. You can define multiple ranges, which are by default treated as an AND, or separate them with a double pipe (||) to act as an OR.
Hyphen Range1.0 - 2.0Creates an inclusive set of versions.
Wildcard1.0.*A pattern with a * wildcard. 1.0.* is the equivalent of >=1.0 <1.1.
Tilde operator~1.2.3"Next Significant Release": Allows the last digit to increase, so becomes the same as >=1.2.3 <1.3.0. The last digit is allowed to increase.
Caret operator^1.2.3"Next Significant Release": Similar to the tilde operator but assumes semantic versioning and that all changes up to the next major version should be allowed, so becomes the same as >=1.2.3 <2.0.

Package stability

Another consideration for configuring Composer to get exactly the libraries that your project needs is how stable you want the library releases to be. You can request beta or development branches of a package if you need the cutting-edge version or are helping to test software. You specify a stability flag by adding it to the end of your require string with a @. For example, to request the latest development version of PHPUnit, you can specify:

{
   "require": {
      "phpunit/phpunit": "4.8.*@dev"
   }
}

For reference, Packagist shows you which branches exist and the string you need to use to reference them, as you can see in Figure 1.

Version locking

One of the great benefits of using Composer is that you don't need to include third-party libraries in your version control. When publishing a new installation of your software, you can keep the version control clean by allowing Composer to download and configure all of the libraries for you. However, you can run into problems. Imagine running 20 concurrent servers for your website, all using different versions of libraries because the code was deployed, and composer install run, at different times. Or more simply, multiple developers could all have different libraries and be unable to replicate one another's bugs. The results can be catastrophic.

Composer provides a solution to this problem. Recall from the "Configuring Composer for your own projects" section that the initial run of composer install creates a composer.lock file. This file specifies exactly which libraries were installed and what specific versions were downloaded in the process. When you commit your project into your version-control software, commit the composer.lock file but not the vendor directory. When a new deployment of the code is prepared, and composer install is run, Composer will look first for a lock file. If it finds it, it will install an exact duplicate of the original installation, thereby ensuring consistency across your installs.

Of course, a way to move on to newer versions of code is also needed — preferably something better than deleting the lock file and the entire vendor directory. Composer provides this facility in the form of the update command. When you run composer update, Composer compares the version of the software installed via the lock file against the latest configuration in the JSON file. If newer versions of software are available that the configuration allows (or if new libraries have been added to the configuration since the last install), Composer downloads the new libraries and configures them in place.

Creating an autoloader for your own classes

Composer has many more features built into it that you can read up on in the documentation. One of the best features is that you can specify your own classes into the configuration, which enables Composer to build your project's code into its autoloader automatically. This feature spares you from needing to create your own autoloader independent of Composer.

Here, I update the previous composer.json file to create my own autoloader:

{
  "require": {
    "michelf/php-markdown": "1.4.*"
  },
  "autoload": {
    "psr-4": {"Converter\\": "src/"}
  }
}

In this example, I specify a namespace called Converter and indicate that all class files for that namespace exist within the relative directory named src. So if I had a class named Converter\CommandLine, the autoloader would look for that class to be saved in the file system as src/CommandLine.php. This file is now a PSR-4 compliant autoloader that has been generated for me.

Providing your own packages

At this point, I can provide the Markdown-to-HTML converter application as a package on Packagist. (Because the converter is an application, not a library that can be reused, providing it as a package doesn't really make sense — but for the sake of this exercise, pretend that it is a library.) Essentially, through the creation of my composer.json file, the application is itself a package and can be installed. The package name must be in the format of vendor/package. So in my case, I add this to the configuration file:

"name": "EliW/Converter",

A few other configurations are worthwhile to add. You can specify the version of PHP that you require as a virtual package name that Composer will enforce. (Among the many other options, you can force version numbers instead of allowing Composer to assume standard version-control system patterns. And you can provide metadata to make a package listing look complete.) To specify a PHP version number and package up my own converter as its own complete package, I'd do this:

{
  "name": "EliW/Converter",
  "require": {
    "michelf/php-markdown": "1.4.*",
    "php": ">=5.3.0"
  },
}

The configuration is now complete. After I commit my application in an online version-control system such as GitHub, I can log in to my Packagist account and submit my package information to make my application available for others to include in their projects.

Conclusion

In this PHP renewed installment, I've given you the basics of how to use Composer to assemble your projects from third-party libraries. Check out the online documentation to find deeper discussions of Composer's less commonly used features and to find out how you can host your own internal libraries without needing to go through Packagist to help organize your complex code bases.

As this series has progressed, I've shown how PHP itself has evolved, how it's meeting modern security requirements, and how it's also adopting modern dependency-management and package-management systems to handle the ever-increasing complexity of modern code bases. In the next installment, I'll discuss how the PHP ecosystem has evolved to enable developers to manage their deployment and development environments through the use of PuPHPet.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, Open source
ArticleID=1005558
ArticleTitle=PHP renewed: Composer for PHP dependency handling
publish-date=05132015