PHP Composer — Complete Guide to Dependency Management
In this tutorial, you will learn about PHP Composer. We cover key concepts, practical examples, and best practices to help you master this topic.
PHP Composer is the industry-standard dependency manager for PHP that installs, updates, and autoloads third-party libraries and packages into your projects. This tutorial walks you through installing Composer, understanding composer.json and composer.lock, requiring and updating packages, leveraging PSR-4 autoloading for your own code, creating and publishing packages, and following semantic versioning for reliable dependency resolution.
What You'll Learn
- Installing Composer globally and understanding the composer.json schema
- Requiring, updating, and removing packages with version constraints
- Understanding the difference between composer.json and composer.lock
- Configuring PSR-4 autoloading for your own source code
- Creating a custom package and publishing it to Packagist
- Using scripts hooks for automated build steps
Why It Matters
Before Composer, PHP developers copied library files manually, leading to version conflicts, abandoned updates, and security vulnerabilities. Composer solves these problems with a single command: composer require. It resolves dependency versions mathematically, generates an optimized autoloader, and ensures every developer on your team uses identical library versions. This is how modern PHP projects, from Laravel to Symfony to Drupal, manage their dependencies.
Real-World Use
DodaZIP, the compression tool suite, depends on 12 Composer packages for encryption, file format detection, and cloud storage integration. Composer's lock file ensures that every build, whether on a developer laptop or a CI server, uses the exact same library versions. When a security patch is released for one dependency, a single composer update propagates the fix across the entire application.
Learning Path
flowchart LR A[Debugging] --> B[Composer\nYou are here] B --> C[PSR Standards] style B fill:#f90,color:#fff
Installing Composer
Download and install Composer globally:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
php -r "unlink('composer-setup.php');"
Verify the installation:
composer --version
Output:
Composer version 2.8.0 2026-05-15 14:08:33
Creating a composer.json
Every project begins with a composer.json file. Create one with composer init:
composer init --name="myapp/demo" --type="project" --description="A demo project" --no-interaction
This generates:
{
"name": "myapp/demo",
"description": "A demo project",
"type": "project",
"require": {}
}
The name field uses the format vendor/package. Composer uses this to identify your project and its packages.
Requiring Packages
Add a package with composer require:
composer require monolog/monolog
This command downloads the monolog/monolog package with the best compatible version, updates composer.json, and generates composer.lock. The lock file records the exact version of every installed package:
{
"require": {
"monolog/monolog": "^3.0"
}
}
Use the package in your code:
<?php
require __DIR__ . '/vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('app');
$logger->pushHandler(new StreamHandler(__DIR__ . '/app.log', Logger::WARNING));
$logger->warning('This is a warning message');
$logger->error('This is an error message');
Output (file app.log):
[2026-06-28T12:00:00.000000+00:00] app.WARNING: This is a warning message []
[2026-06-28T12:00:01.000000+00:00] app.ERROR: This is an error message []
Understanding Version Constraints
Composer supports several version constraint formats:
| Constraint | Meaning |
|---|---|
^3.0 |
Compatible with 3.0 up to 4.0 (exclusive) |
~3.0 |
Compatible with 3.0 up to 3.9999 |
>=3.0 <4.0 |
Explicit range |
3.0.* |
Any 3.0.x version |
dev-main |
Development branch (add "minimum-stability": "dev") |
Run composer update to upgrade all packages within their constraints:
composer update
Configuring PSR-4 Autoloading for Your Code
Composer can autoload your own classes. Add the autoload section to composer.json:
{
"name": "myapp/demo",
"description": "A demo project",
"type": "project",
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"require": {
"monolog/monolog": "^3.0"
}
}
Generate the autoloader:
composer dump-autoload
Now create a class at src/Models/User.php:
<?php
namespace App\Models;
class User
{
public function __construct(
private string $name,
private string $email
) {}
public function getName(): string
{
return $this->name;
}
public function getEmail(): string
{
return $this->email;
}
}
Use the class without requiring the file:
<?php
require __DIR__ . '/vendor/autoload.php';
use App\Models\User;
$user = new User('Alice', 'alice@example.com');
echo $user->getName() . ' - ' . $user->getEmail();
Output:
Alice - alice@example.com
Creating and Publishing a Package
Create a reusable package. Structure:
my-package/
composer.json
src/
Greeting.php
composer.json:
{
"name": "myapp/greeting",
"description": "A simple greeting library",
"type": "library",
"autoload": {
"psr-4": {
"MyApp\\Greeting\\": "src/"
}
},
"require": {
"php": ">=8.1"
}
}
src/Greeting.php:
<?php
namespace MyApp\Greeting;
class Greeting
{
public function say(string $name): string
{
return "Hello, $name! Welcome to Composer packages.";
}
}
Publish to Packagist by pushing the code to a public GitHub Repository and submitting the repository URL at https://packagist.org/packages/submit. Once approved, anyone can install it:
composer require myapp/greeting
Using Composer Scripts
Define scripts to automate common tasks:
{
"scripts": {
"test": "vendor/bin/phpunit",
"lint": "phpcs --standard=PSR12 src/",
"check": ["@lint", "@test"]
}
}
Run them with:
composer test
composer lint
composer check
Common Mistakes
- Committing vendor directory: The vendor directory should be in .gitignore. Other developers run
composer installto recreate it from composer.lock. - Forgetting to commit composer.lock: Without the lock file, different developers may get different versions, causing "it works on my machine" bugs.
- Using dev-master without minimum-stability: Composer ignores dev branches unless you set
"minimum-stability": "dev"in composer.json or use"dev-master"as the version constraint. - Not running composer dump-autoload after adding classes: PSR-4 autoloading needs a fresh autoloader file after new classes are created. Run
composer dump-autoload. - Over-constraining versions: Using exact versions like
"1.2.3"prevents security patches. Prefer^1.2for flexibility within major versions.
Practice Questions
What is the difference between composer install and composer update?
composer installreads composer.lock and installs exact versions.composer updaterecalculates dependencies and overwrites composer.lock.
How do you add a package only for development?
- Use
composer require --dev phpunit/phpunitto add it to therequire-devsection.
- Use
What is the purpose of the autoload section in composer.json?
- It tells Composer how to load classes automatically using PSR-4, PSR-0, classmap, or files autoloading strategies.
How do you remove a package?
- Run
composer remove vendor/package. Composer removes the files and updates composer.json.
- Run
Challenge: Create a custom Composer package that provides a Markdown-to-HTML converter. Publish it to a private Satis repository and require it from another project.
Mini Project
Build a command-line CSV processing tool that uses Composer dependencies:
- Require
league/csvfor CSV reading and writing. - Require
symfony/consolefor CLI command handling. - Require
monolog/monologfor logging. - Create a
CsvProcessorclass in theApp\namespace that merges two CSV files by a common column. - Configure PSR-4 autoloading for the
App\namespace. - Write a console command that accepts input file paths and an output file path.
FAQ
What's Next
Now that you can manage dependencies, learn the coding standards that make PHP packages interoperable with PSR Standards.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro