Composer: How to Install in Different Ways
Composer, the most important tool for PHP developers, offers three methods to install packages:
- local
composer require vendor/name
- global
composer global require vendor/name
- as a project
composer create-project vendor/name
Local Installation
Local installation is the most common. If I have a project where I want to use Tracy, I enter in the project's root directory:
composer require tracy/tracy
Composer will update (or create) the composer.json
file and
download Tracy into the vendor
subfolder. It also generates an
autoloader, so in the code, I just need to include it and can use Tracy
right away:
require __DIR__ . '/vendor/autoload.php';
Tracy\Debugger::enable();
As a Project
A completely different situation arises when, instead of a library whose classes I use in my project, I install a tool that I only run from the command line.
An example might be ApiGen for generating clear API documentation. In such cases, the third method is used:
composer create-project apigen/apigen
Composer will create a new folder (and thus a new project)
apigen
and download the entire tool and install its
dependencies.
It will have its own composer.json
and its own
vendor
subfolder.
This method is also used for installations like Nette Sandbox or CodeChecker. However, testing
tools such as Nette Tester or PHPUnit are not installed this way because we use
their classes in tests, calling Tester\Assert::same()
or inheriting
from PHPUnit_Framework_TestCase
.
Unfortunately, Composer allows tools like ApiGen to be installed using
composer require
without even issuing a warning.
This is equivalent to forcing two developers, who don't even know each other
and who work on completely different projects, to share the same
vendor
folder. To this one might say:
- For heaven's sake, why would they do that?
- It just can't work!
Indeed, there is no reasonable reason to do it, it brings no benefit, and it will stop working the moment there is a conflict of libraries used. It's just a matter of time, like building a house of cards that will sooner or later collapse. One project will require library XY in version 1.0, another in version 2.0, and at that point, it will stop working.
Global Installation
The difference between option 1) and 2), i.e., between
composer require
and composer global require
, is that
it involves not two, but ten different developers and ten unrelated projects.
Thus, it is nonsensical squared.
Because composer global
is a bad solution every time, there is
no use case where it would be appropriate. The only advantage is that if you add
the global vendor/bin
directory to your PATH, you can easily run
libraries installed this way.
Summary
- Use
composer require vendor/name
if you want to use library classes. - Never use
composer global require vendor/name
! - Use
composer create-project vendor/name
for tools called only from the command line.
Note: npm uses a different philosophy
due to JavaScript's capabilities, installing each library as a “separate
project” with its own vendor
(or node_modules
)
directory. This prevents version conflicts. In the case of npm
,
global installations of tools, like LESS CSS,
are very useful and convenient.