Modern PHP Developer
Table Of Content
1. Package Manager
In general, a block of code forms a method, a group of methods forms a class and a set of classes form a package.
A reusable package can be dropped into any project and be used without any need to add functionality to it.
A package exposes APIs for clients to achieve a single goal.
Packages help our applications achieve DRY (Don't Repeat Yourself), a principle of software development, which reduces repetition of information of all kinds.
In most cases, packages have dependencies. When "Package A" requires "Package B" in order to work, we say "Package A" depends on "Package B". It is quite common to see that a package has a chain of dependencies("Package A" depends on "Package B", "Package B" depends on "Package C", the list goes on).
Imagine there is no such thing as a package manager. What would we need to do in order to get "Package A", which has a dependency of "Package B" to work? First we download source code of "Package A", then discover it depends on "Package B", so we try our best to find source code of "Package B". It might still not work, because we also need to make sure that we download the correct version of "Package B". The story can go on and on. We are only talking about one single dependency here; it would soon turn to be a nightmare if "Package A" has multiple dependencies or there is a chain of dependencies.
We do need a package manager, a package manager that can solve all of these dependency headaches for us.
Composer vs. PEARPEAR
Prior to Composer, there was something called PEAR. If you started with PHP early on, you may be aware of PEAR, as it has been in existence since 1999. PEAR is made for the purpose of promoting reusable packages, similar to Composer. However, it has been discouraged by developers due to the following reasons:
- Unlike Composer, PEAR is a system-wide package manager. When you have multiple projects, which share the same dependencies, but each has different versions, this approach causes a lot of confusion and frustration.
- A certain number of up-votes is required in order to have your code accepted into PEAR's repository. This discouragement slows down growth of its repository. At the end of day, developers want to write code, not promote code.
Composer is an application-level package manager for PHP. It is inspired by NodeJs's NPM and Ruby's Bundler, and is currently the recognized package manager by the community.
The Composer ecosystem consists of two parts: the Composer, which is the command-line utility for installing packages, and the Packagist, the default package repository.
An application-level package manager means it manages dependencies on a per project basis. This makes managing multiple projects easy and keeps your machine clean as it only downloads packages to your project directory.
Everyone is welcome to submit their packages to Packagist. Unlike PEAR, there is no need to get up-votes whatsoever. You do, however, get starts if people like your packages.Packagist
As mentioned earlier, Packagist(packagist.org) is the default package repository for Composer. As of the time of this writing, September 2015, 69,568 packages are available on Packagist. Next time you need a PHP package, instead of building one from scratch on your own, there is a good chance you can find it on Packagist. As a developer, it is recommended you leverage the power of Packagist as it will save you countless hours and energy.
Now, it's time to get our hands dirty.
We will assume you are a Mac user.
There are two scopes when installing Composer: local scope and global scope. From professional experience, we suggest installing Composer globally on your system. After all, it is very likely we will use Composer to manage dependency for every PHP project. Global installation saves us a lot of hassle.Global Installation
Run commands below from your Terminal to install Composer globally:
If you encounter any errors related to permissions, run commands above in sudo mode (append sudo to each command)Local Installation
Run commands below from your project root directory to install Composer locally:
For a more detailed installation guide on Composer, check out: https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osxVerification
To verify if Composer is installed properly, run command below from the directory Composer is installed (Anywhere if Composer is installed globally).
If you see an output similar to the one below, you are ready to go.
Composer is now ready to use. Let's demonstrate its usage through a simple example:
Imagine we have completed an awesome project and we want to generate simulated data, for example, people's names and addresses, to show our client. It would be cool if the data is random and yet makes sense, so the demo would look real. One solution would be to type some fake names and addresses, store them in an array, then pick entries out of the array randomly using array_rand. As you have probably realized, this solution sounds tedious and impractical. What happens if we need hundreds of users' data? We need a savior.
It turns out there is a package on Packagist, which does exactly what we need. The best part is that it is even called Faker.
Let's install Faker using Composer.
From our project root folder, run command:
It will take Composer a few seconds to download the required files. Under the hood, Composer downloads the zip file of Faker from Github. Besides downloading the required package, Composer will also create some internal files, which we will look into later.
Now take a look at our project directory and you should be able to discover some newly created folders and files as shown below:
This file describes the dependencies of your project. It is a simple JSON file and shows you what packages are installed in your project.
Whenever you run
composer require from command line, composer.json and composer.lock will be automatically updated to reflect package change. Conversely, if you add a package to composer.json file,
composer install to download the new package. If you want to update all packages' versions to the latest specified by their version constraints, you can run
There are three basic commands of Composer:composer require
This command is used to add an individual package to the dependencies. Whenever we need a new package, we can just run it. It is convenient because we do not have to touch the composer.json file at all.
Another usage of this command is to update an existing package's version.
For example, we have installed the latest version(1.4.0) of Faker using
composer require fzaninotto/faker as Composer fetchesthe latest version of a package if we do not specify its version constraint. Since our application is incompatible with 1.4.0, we need to install 1.2.0 in order to run
composer require fzaninotto/faker:1.2 0 .
It will download a specific package and update all relevant Composer files accordingly.
This command first looks for composer.lock file, if it is present, exact version of the packages defined, will be installed and composer.son will then be ignored. If it is not present, the command will check packages defined in the composer.json file and download the latest versions of the packages that match the supplied version constraints. Can you spot the difference? When composer.lock is used, exact versions are downloaded, whereas using composer.json, Composer will always attempt to retrieve the latest version of a package that matches the supplied version constraint. When version constraint is defined as an exact number, both actions have the same result. However this is rarely the case.
This command is used when we begin a new project - we define a list of dependencies and run this command to get all packages installed. Or, when kick-start someone else's project, we check out their code from Github and run this command to get all dependencies installed.
In some deployment strategies, we run this command in production to install the application after pulling its source code from repository.composer update
This command only reads from composer.json file which is different from composer install . It updates existing packages to the latest versions that match supplied version constraints defined in composer.json. Meanwhile, it downloads any new packages added to composer.json file.
We can use this command to update existing packages' versions,
The difference is that
composer require does not require us to touch the composer.json file manually, it feels more intuitive.
The fact that this command only reads from composer.json brings up a common pitfall, which is running this on production. We should never run composer update in production. Here's why:
If your application is working well with Faker 1.2.0 on your local development environment,
you push your code to production and run
Without your knowledge, the latest version of Faker has already been updated to 1.4.0, so Composer downloads version 1.4.0 of Faker in production, because you have defined its version constraint as 'fzaninotto/faker: 1.*' in composer.json. As a result, your production is now using a different package from your development. This is not the intended outcome.
We recommend deploying composer.lock along with compose.json and running
composer install in production. This will ensure your production has the same packages as your development.
While composer.json file lets us define packages we need using versions constraints, composer.lock tracks exact versions of packages installed in our project. In other words, it stores the current state of our project. This is a very important point to remember.
The fact that
composer install reads first from composer.lock, makes it a much safer command to use. Here's why:
If you delete vendor completely from the project,
this will remove all packages Composer downloaded. Now run
composer install again and it will obtain the exact versions of packages as it previously did.
This brings up our next point. If we are using a version control system such as Git, should we commit composer.lock?
The answer is "It Depends". Most of time we want to make sure everyone is sharing identical source code at anytime. So we will commit composer.lock. This is very common since most of us work with a team. The rare case of not committing composer.lock is when we develop a package(library), because users rarely need to run
composer install in our package.
Composer gives us a lot of flexibility in using its commands, however there are a couple of rules we try to follow to prevent liability.
composer installis our friend - use it in production for deployment.
A fair standard Composer workflow:
- Defined some dependencies in composer.json: run
- Need an individual package: run
composer require some/package
- Need multiple packages: define them in composer.json file and run
Want to test out one single newly released package:
composer require some/package:new-version
Ready to test out all the latest versions of packages released:
You have probably used a lot of
include/require statements. The problem with These statements is that, they make our code cluttered. And the worst part is, whenever we update our directory structure, we end up doing a lot of find&replace work.
The solution is autoloading. It allows you to define paths to search for classes so you do not have to do it manually with
include/require. But of cause, we should keep in mind that under the hood, autoloading is still using
Now, let's jump back to our awesome project. There is one place we have not really explored yet, and that is the vendor directory created by Composer. By default, Composer downloads all packages to this directory.
Composer also generates a vendor/autoload.php file, which provides autoloading to us for free, making it really easy to use vendor code.
In our case, we want to use Faker so we can simply include the below file and Faker will be autoloaded.
Now we can just start using Faker.
Power of community
You should now have a fair understanding of Composer. Start using it to manage your project's dependencies. We guarantee it will make your and your co-workers' lives much easier. Next time your project needs something, start looking for them on Packagist. Embrace the power of community!
Hopefully this simple tutorial helped you with your development.
If you like our post, please follow us on Twitter and help spread the word. We need your support to continue.
If you have questions or find our mistakes in above tutorial, do leave a comment below to let us know.