Composer—an overview

At the time of writing the latest version of Composer is 1.6: information may not be entirely accurate for later versions.

What does it do

Composer is the primary PHP package manager, succeeding PEAR for the installation of most PHP packages (with the exception of PECL packages).

Composer is an object-oriented package manager—it takes advantage of the PSR-0 and PSR-4 functionality in PHP to implement an autoloader to pull in classes from the vendor directory. One of the first things you have to do if you want to use composer for your project is to include this snippet of code:

require __DIR__ . '/vendor/autoload.php';

This then registers its own autoloader via spl_autoload_register(), and handles all loading of composer package code when you try and include something with use.

Packages are registered via https://packagist.org/. You can create both public and private packages, so if you have code that should only be shared with a small group or within your company you can still host it as a composer package.

You can also pull in packages directly from various version-control systems.

Creating a package

Creating and publishing a basic package is fairly straightforward. First, create an account on packagist.org. I'm going to assume that you have a GitHub account, but it should be fairly straightforward to follow the directions to use this for other code repositories.

Now, on your machine, create a directory for your package. Then, run composer init. Fill out all of the relevant information, and give your package a sensible name (for example, janedoe/my-first-package). Within your directory, create another directory called src. This is where your package code will live.

Now edit your composer.json—you need to manually add the autoloading information. Assuming you're using PSR-0, add the autoload section to your metadata. It should look something like this:

"autoload": {
  "psr-4": {
    "MyNamespace\\": "src/"
  }
}

Replace MyNamespace with your chosen root namespace. Remember to include this in your code.

Now you can start writing code, following the PSR-4 structure. For example, if you wanted to have a class MyNamespace\Speech\Writer, you would create a directory Speech in src containing the file Writer.php. Inside this file would be:

<?php

namespace MyNamespace\Speech;

class Writer {
  public static function write() {
    echo "Hello\n";
  }
}

Commit your code and push it to your GitHub repository (run composer validate before doing so to pre-empt any validation issues). Create a Release on the Releases page following the semver convention, and then add your package to Packagist using your GitHub URL. You should see the release you created pulled though as the latest version.

Now you can install your package using composer install. You can then write some code that invokes it. From the same level as your vendor directory, create a file called index.php containing something like:

<?php

require __DIR__ . '/vendor/autoload.php';

use MyNamespace\Speech\Writer;

Writer::write();

If you run this script in the terminal, you should see "Hello" returned.

See this GitHub repository for an example of some basic package code.

Language

Composer is written in object-oriented PHP.

Architecture

The architecture of the composer command is fairly straightforward—in the bin directory of the repository is the main composer file. From here, the composer application (Composer\Console\Application) is started.

The Application is based on the Symfony Console Application class, and exposes the classes in src/Console/Commands via the getDefaultCommands() method.

You can see all individual command classes within the src/Composer/Command directory. These are all Symfony Console Commands.

bin/composer
└─ src/Composer/Console/Application.php
   ├─ src/Composer/Console/Command/AboutCommand.php
   ├─ src/Composer/Console/Command/ArchiveCommand.php
   ├─ ...

The composer command is distributed as a Phar (PHP Archive)—a packaged PHP application. This is built using the bin/compile script.

Security

There are currently no explicit security mechanisms to verify package contents (see this open GitHub issue).

As such, your best security measure is to avoid using rolling versions where possible, and instead pin your composer.json to a single version or a fixed range. This will ensure that you must explicitly update packages, rather than having new versions added by composer update as they become available.

For most casual use cases this is probably overkill, and you can instead rely on your lockfile, but make sure you're checking your composer update with composer update --dry-run and monitoring CHANGELOGs for updated projects.

If you're distributing your project for others to use, having a maximum package version is probably the way to go to prevent unintended issues when new versions of dependencies are released.

Since packages are effectively just code repositories a couple of compromised accounts could easily allow a malicious actor to add and distribute code to a popular package, so having a maximum version also serves as a security measure (as even if the release tag is deleted and replaced, the commit hash will differ from the one in your composer.lock file).

In the same vein it's best to avoid enabling dev packages unless explicitly required, since every commit can then potentially cause changes if you update your packages.

Custom repositories

Whilst package provides an easily solution to hosting Composer packages, you may want to create your own package repository if you have a large amount of code that you want to have more control over, or to keep private. There are various tools that can help you, but effectively all you need is a manifest (packages.json) describing the available packages and where they can be retrieved. You can then add this to your composer.json in the repositories section. For example, for Drupal packages:

"repositories": [{
  "type": "composer",
  "url": "https://packages.drupal.org/8"
}],

Can also use custom types:

composer search token --type=drupal-module

Useful commands

composer require is what you'll call to add packages to your composer.json file and install them to your project. This will also update your composer.lock file.

require will take care of resolving the required package with existing package dependency versions. You can call it with specific versions (e.g. composer require "drush/drush:9.*"). You can also call it without installing the package by passing the --no-update flag.

composer install installs the packages as specified in your composer.lock file (if a lock file doesn't exist it will install based on your composer.json and create a lock file). You should always store your lock file, since it will ensure that all developers are getting the same versions of packages when they run install.

composer update will update your installed packages to their latest compatible versions, and composer.lock file. You can restrict it to a particular package or set of packages by passing the package names as arguments.

update can also be used when your composer.json file changes—for example, when you've manually updated a version or conflict—and will take care of resolving dependency issues and updating your composer.lock file accordingly.

composer remove lets you remove packages from your composer.json and composer.lock file.

composer search lets you search your projects package repositories by package name or keyword. By default this will just search Packagist, but you can add other repositories in the repositories section (see above).

composer show lists information about currently installed packages.

composer init helps you generate a composer.json file for a new project.

There are plenty of other composer commands, but these are the ones I find myself using on a regular basis.

Further information

http://naderman.de/