aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Development

PHP Composer: A Practical Dependency Management Guide

PHP Composer is the backbone of modern PHP development: a dependency manager that downloads the libraries your project needs, manages their versions, and loads your classes automatically. What NPM does for JavaScript, Composer does for PHP. In this guide we cover everything you need for daily use — from installing Composer from scratch and adding packages with require, to the logic behind composer.lock and PSR-4 autoloading — with real, working examples.

What is Composer and why do you need it?

In the old days, using a PHP library meant downloading files by hand and pulling them in one by one with require. That approach was error-prone and turned version upgrades into a nightmare. Composer solves three core problems:

  • Dependency resolution: it automatically finds the other packages a package needs (and their dependencies too) and installs compatible versions.
  • Version management: you define which versions are acceptable, and Composer picks the best one that satisfies that rule.
  • Autoloading: it loads your classes and packages by name, without you having to require each file manually.

Packages are pulled from a central repository called Packagist (packagist.org). The entire ecosystem — Laravel, Symfony, Guzzle, PHPUnit — is distributed from there.

Installation and your first project

You can install Composer based on your operating system: there is an official install script for Linux/macOS and a ready-made installer for Windows. To verify the installation:

composer --version

When starting a new project you can run an interactive wizard or generate a composer.json directly:

composer init

This command asks for the package name, description, license, and initial dependencies, then creates a composer.json file in the root directory. That file is your project's ID card; dependencies, autoload rules, and metadata all live there.

Installing packages: require and install

The most direct way to add a package is the require command. For example, to install the popular HTTP client Guzzle:

composer require guzzlehttp/guzzle

This downloads the package, adds it to composer.json, updates composer.lock, and places it in the vendor/ folder. You can also pin a version constraint:

composer require guzzlehttp/guzzle:^7.5

Add tools needed only during development (test libraries, code analyzers) with --dev; these are excluded from production installs:

composer require --dev phpunit/phpunit

When you clone a project, you use install to set up its dependencies. This command reads the exact versions from composer.lock and installs them verbatim:

composer install

On a production server, the common combination to skip development dependencies and optimize autoloading is:

composer install --no-dev --optimize-autoloader

composer.json vs composer.lock

Mixing up the roles of these two files is the most common source of confusion. composer.json describes your intent: "any 7.x version of Guzzle is fine." composer.lock records the current reality: "Guzzle 7.8.1 was installed, exactly." A typical require section looks like this:

{
    "require": {
        "php": "^8.2",
        "guzzlehttp/guzzle": "^7.5",
        "monolog/monolog": "^3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0"
    }
}

The meaning of the version operators is critical:

  • ^7.5 — 7.5 and above, but less than 8.0. The most common "allow compatible updates" operator.
  • ~7.5 — 7.5 and above, but less than 7.6 (patch releases only).
  • 7.5.* — any patch in the 7.5 series.

Golden rule: always add composer.lock to version control (Git). That way everyone on the team and the production server installs the same versions, preventing "it worked on my machine" problems.

When to use update vs install?

The distinction between the two is the heart of dependency management. composer install stays faithful to the lock file and changes no versions. composer update upgrades packages to the newest compatible versions allowed by composer.json and rewrites composer.lock:

composer update

If you only want to update a single package, name it:

composer update monolog/monolog

Never run composer update on a production server. Because that command changes versions, it can cause unexpected breakage in a live environment. Do the update locally, test it, commit the new composer.lock, and run only composer install on the server.

Autoloading: your own classes with PSR-4

Composer's most powerful feature is autoloading. To have Composer load your own classes too, add a PSR-4 mapping to composer.json. This binds a namespace prefix to a folder:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

This mapping means: the class App\Services\Mailer is looked up in src/Services/Mailer.php. After adding the mapping, you must regenerate the autoload map:

composer dump-autoload

Now a single line at your project's entry point is enough. Including Composer's generated autoloader loads both your own classes and all packages automatically:

require __DIR__ . '/vendor/autoload.php';

use App\Services\Mailer;

$mailer = new Mailer();

For production performance, the --optimize-autoloader (or -o) flag pre-computes the class-to-file map, eliminating filesystem lookups at runtime.

Automation with Composer scripts

The scripts section inside composer.json lets you define shortcuts for commands you run often:

{
    "scripts": {
        "test": "phpunit",
        "check": [
            "@php -l src/",
            "phpunit"
        ]
    }
}

You run these with composer test or composer check. Event hooks like post-install-cmd are also used to trigger automatic tasks after installation — Laravel generating a key after setup is one example.

Frequently Asked Questions

Should I commit composer.lock to Git?

Yes, absolutely. In application projects, composer.lock should always be committed; this guarantees that every developer and the production server installs exactly the same versions. Only if you are building a library (a package) for others to use is it a common choice not to commit composer.lock.

I'm getting a "Class not found" error — why?

The most common cause is a stale autoload map. If you added a new PSR-4 namespace or renamed files/folders, run composer dump-autoload. Also make sure the namespace matches the file path and class name exactly, including capitalization.

What is the difference between require and require-dev?

require holds packages the application needs to run in every environment. require-dev holds tools needed only during development (PHPUnit, static analysis, debuggers). In production, composer install --no-dev skips those development dependencies, making the install lighter and more secure.

Has dependency management in your PHP project become a tangle? If you need help with Composer setup, autoload configuration, version conflicts, or a clean architecture for a Laravel/Symfony-based project, get in touch with me — let's put your project on a solid foundation together.

Bu kategorideki tüm yazılar →

Devamı için