19 July 2014 —
One of the common problems we have to confront when starting a new PHP project is how to handle the different dependencies we are going to have.
One could think the easier solution is to download all the libraries we are going to need, put them in a lib
directory and add them to the version control of the project, but this could be problematic. Let’s see why.
The main problems of using this practice are this.
- Dependencies of dependencies: Our dependencies may have their own dependencies that we will also need to download.
- Updates: What happens if we need a new feature in the last version of one dependendency? We are going to have to update it manually, and that can be a hard task. Baybe even the new version has new dependencies of its own that we will need to download.
- Autoloading: How do we deal with autoloading the classes in the dependencies? Some of them may have its own autoloading system, but anyway, we are going to need to
include
all the autoloaders of each dependency.
How do we solve all of this? The answer is Composer.
Starting with composer
Composer has become the dependency manager in the main PHP projects. It uses its own library repository (packagist) to handle dependencies, but you can setup private repositories too.
It uses a small configuration file, the composer.json
, to know which are our dependencies, and it will download their dependencies recursively without us having to do anything special.
We can define an autoloading strategy in that file too, and forget about that task for our project and our dependencies.
This are some examples of famous PHP project’s composer.json
files:
Now lets see a simpler composer file:
This is the composer file of my Zend Framework 2 module AcMailer. Let’s explain it.
The properties name, description, type, authors, keywords, homepage and license are just metadata to provide useful information to other users and ease finding the project in packagist.
The require property is the place where we define our dependencies and the version we want to install. We can define here the minimum required PHP version and even the php modules we need (like php-pdo
, php-intl
and such).
The require-dev property allows us to define other dependencies that won’t be necessery in a production environment, like testing or documentation tools.
Finally the autoload property is where we define how our own classes are loaded. It is very easy to define a psr-0
or psr-4
autoloading strategy, but we can even define a classmap
with a list of paths to files.
You don’t have to remember the
composer.json
schema. You can interactively create it by runningphp composer.phar init
.
Installing dependencies
Once this is defined we just need the composer binary file (usually in phar format), that can be found here, and run php composer.phar install
.
This will create a vendor
folder in the root of our project, download our dependencies there, the dependencies of our dependencies, and set-up an autoloader that will be able to load all our dependencies and our own classes as well.
After this it’s enough with a single include
statement to vendor/autoload.php
to be able to access any class.
If later in the project we need to update an existing dependency, add new dependencies or change the autoloading, we just need to update the information in the composer.json
file and run php composer.phar update
to update dependencies and autoloader.
It is recommended to include the composer binary in the PATH to be able to run
composer
instead ofphp composer.phar
.
If you are using a VCS like git in your project you will probably want to ignore your
vendor
folder.
Advanced usages
This should be enough to start working with composer, but it is a much more powerful tool with more features. It is not a bad idea to take a quick read to its documentation, but let’s see the main advanced features.
- Classmap autoloader: By running
composer dumpautoload --optimize
we can generate a much faster autoloader which defines a class => file map array with all the classes handled by composer. This is the more suitable autoloader for production environments. - Production dependencies: If we include de modifier
--no-dev
while installing or updating dependencies, it will ignore (or remove) the require-dev dependencies. For examplecomposer update --no-dev
- Private repositories: If you want to install dependencies from repositories other than packagist, you can do it by using the repositories property. It supports many types of repositories, from VCS to PEAR repositories. Complete documentation here.
- Global packages: If you want to install dependencies globally, just add the
global
keyword before theinstall
orupdate
. That will install the dependencies in the~/.composer/vendor
directory instead of installing them in the localvendor
directory. For examplecomposer global update
.
And that’s all you need to know to start working with composer.
Update 2015-04-25: I’ve written an article addressing advanced concepts that is a good continuation to this one. Composer advanced concepts.