What, why and how of PHP Composer

What, why and how of PHP Composer

Let's demystify the package manager Laravel and other frameworks use

Since developers have realized the power and benefits of the DRY approach, lots of frameworks and libraries have been crafted privately and open-source.

If you're someone like me (myself 2 years ago to be precise), you might say - "Why all these new frameworks are not allowing a direct .zip download? Why do I have to install (and learn) this new Composer thing just to download a framework?"

Back in the days when I was using Codeigniter and CakePHP 2, I would just download .zip file, extract it in my project directory and start developing. So neat, right? Read on.

Then, I witnessed new version CakePHP 3 in 2015 (so unlucky I didn't try Laravel that time). It was forcing me to use composer to download the framework and I was very new to it. I was complaining, like others, until I realised how much time and headaches it is going to save for me.

What it Composer?

Composer is a dependency manager and autoloading expert for PHP.

Have you heard about or used npm? (or yarn) Or if you're a Rubyist, Bundler must not be new to you. Composer provides similar functionality for the PHP world. It used to be PEAR (PHP Extension and Application Repository) in early days.

One important thing to note here is that the open-source packages generally recide on Packagist and composer downloads the dependencies from there, unless you specify other location. Packagist, in turn, keep and updates the code from Git/Svn repositories. And you can also use private repository with composer by using Private packagist or hosting them yourself.

I hate theory. Let's have some practical talk.

Pains that Composer fixes

Following are some of pains that Composer has relieved:

Dependency Management

Dependency Management

When you are working on a new project using a framework, you depend on it's updates. As they release new versions with bug fixes and new features, you should keep the framework updated for security, performance, and other reasons.

But, it's a pain to manually download it everytime, replace the existing files and test things again. It takes time. And that is why there are so many old codebases relying on the versions of frameworks that are no longer supported. Working on legacy projects is something that all of us try to avoid, isn't it?

Project directory size

Project directory size

Pre-composer days, the size of the project directory used to be very big. We would carry all the libraries that our project depends on and pass around the project either in USB sticks or pollute the VCS (git) history.

Enter Composer - Size reduces to less than 20%? We can get away without keeping the dependencies in the project (.gitignore) and avoid version mismatches at the same time thanks to composer.lock file.

sad fact - Codeigniter 3 still uses the traditional download system.

Hours of debugging

The libraries or frameworks that your project uses depend on some other libraries (and the chain continues...). Possibly, the framework is using version X of a library while another library is using version Y of the same library.

You have been getting errors due to some clash or incompatibilty and have to put a lot of time to get to the base of the issue. No more - composer keeps only one copy of a library with a suitable version or denies the installation request.

Autoloading

Remember that long list require statements? As the project grows in size, so does the number of files we need to include in each of the file. PHP autoloading came to the rescue but still it was comparatively hard to setup and maintain as dependencies grow. Less discussed powerful feature of Composer is Autoloading. It supports PSR-0, PSR-4, class mapping as well as files autoloading. We need to require just one file and we're done. Play with straightforward namespaces and enjoy the development time.

Less known fact - Composer provides three different levels of autoloader optimisation for your different level of needs.

Lengthy Installation procedures

Lengthy Installation procedures

Often times, one or more steps need to be followed after downloading a library for setup and installation. Package maintainers had to write detailed installation procedures in the documentation and still answer support queries when users won't follow them and then complain about errors. Composer scripts are a boon for them.

One can easily code the steps that can be automated and run as a script during various stages of the package download. For example, Laravel uses composer scripts to create an .env file, create an application key, and perform automatic discovery of the packages.

Platform Requirements

The code of your library/package may support only latest PHP versions or depend on specific PHP extensions. And you can inform Composer about this resulting in prevention of package downloads on the systems that don't meet the requirements. For example,

"require": {
    "php": "^7.1.3",
    "ext-mbstring": "*",
    "ext-openssl": "*",
    ...
},

Add this to your composer.json and composer will throw an error when the systems with PHP less than v7.1.3 or without mbstring and openssl extension try to download the package.

Maintaining a library/package

Maintaining a library package

Package maintainers had to either maintain different directories for each version of the package or release new versions through GitHub everytime there was an important update. Thanks to the graceful integration of Composer with VCS tags and branches, one just needs to add a tag to the commit and push. The rest is taken care of.

Composer highly recommends Semantic Versioning and following that, package maintainers can keep focus on actual development without worrying about the distribution.

Marvellous. I do not have complains any more and am ready to jump in. What next?

Nuts and bolts of Composer

Now that we have an idea about what and why of the Composer. Let's jump into the how part:

Installation

The installation instructions on the composer documentation are pretty clear and I think my best job is to link you there.

Consumption

If you want to build a project using Laravel, you need to install it using composer. Though some people want to go with the traditional way, it is highly discouraged.

Laravel itself uses lots of useful open-source package like PHPUnit, Monolog, Carbon, etc. Those dependencies are also managed by composer. You should learn about version management to avoid potential issues.

Fun Fact - Composer installs dependencies in the vendor directory by default but it also supports custom installers for various package types that can install dependecicies in other directories.

Version management

Understanding how composer downloads the libraries based on the version constraints specified in your composer.json file will help you a long way. I recommend you to go through the original documentation article at least once.

Did you know? - You can require a package by its version, branch or even by a specific commit SHA (not recommended).

Personally, my suggestion is to use Caret Version Range (^) for the packages which use Semantic versioning and Wildcard Version Range (.*) for others as they are easy to grasp.

Understanding composer.lock file

While composer.json is managed automatically when you use the create-project command or when you directly require a package from the terminal. composer.lock is something you should be aware of.

First of all, you should commit your composer.lock file to make sure that everyone of your team members use the same copy of the dependencies while working on a common project. How does that happen?

Whenever you run composer install, Composer actually checks for the existence of the composer.lock file. If it is present, it installs all the dependencies as per the lock file which contains exact version numbers and SHAs to be used. If lock file is not present, Composer simply reads the composer.json file, installs the dependencies and creates the composer.lock file. Next time you run the install command on server or some other computer, lock file is used to give you the exact same copy.

On the other hand, composer update command looks at the composer.json file directly, installs the new versions of the dependencies, if available, as per the version contstraints and updates the lock file.

Slowness of Composer

Slowness of Composer

I have experienced slow installs and updates by composer. Unknown about what's going on in the background, I would just keep staring at the screen as I wait for it to complete before I can take my next step.

If you're facing the same issue, I suggest you to append the composer command with --profile and -vv or even -vvv to have more information about background processing. For example,

composer install -vv --profile

If you cannot find any specific issue from the output, you can also try this package to enable parallel downloads.

Package development

If are just starting out building your first package/library, there is a very useful tip to make the development easy and comfortable.

Most of the times, the package/library needs to be tested against an actual project during development and for that - maintainer may need to keep the package inside the actual project to avoid unnecessary multiple releases until he's done.

Composer Path repositories can save yourself from that trap. It will Symlink or Mirror the repo in the project and you can keep the code bases separate and manage and switch them easily.

Laravel super artisan Caleb Porzio even added a bash alias to use this feature with a single command.

Quick tip - If your package contains a command line script which you would like to pass along to the users, consider using vendor binaries. PHPUnit uses it to quickly let you fire vendor/bin/phpunit.

Branch Aliasis

Once your package/library is already being used by multiple projects, you should also consider adding branch aliasis to make developers' life a bit easier. This article explains the reason behind it very well and also specifies how to do it.

Advanced level developers - Composer allows you to alter or expand it's functionality by using composer-plugins. You can perform actions when your package is loaded and when certain events are fired.

Final notes

This was a bit longer one. We covered quick history about dependency management, learned what Composer is, discussed about the pains that it fixes and then went through some useful points and tips around composer for the new developers and package maintainers.

That is pretty much what I had to say. If you've reached here all the way from the top reading each line, thank you. I think our thinking style matches. Say hi in the comment section below.

If you have any questions, feel free to post your comment, I would try my best to solve your queries.

And If you think this can help other developers in your online network, I’d be happy to see you sharing this with them. Thanks.