intermediate Step 11 of 16

Composer and Dependency Management

PHP Programming

Composer and Dependency Management

Composer is the standard dependency manager for PHP, similar to npm for JavaScript or pip for Python. It handles package installation, version resolution, autoloading, and project configuration. Composer uses a composer.json file to define your project's dependencies and a composer.lock file to ensure reproducible installs across different environments. Understanding Composer is essential for modern PHP development — every major framework and library uses it, and it provides PSR-4 autoloading that eliminates the need for manual require statements.

Getting Started with Composer

# Install Composer (macOS)
brew install composer

# Or download from getcomposer.org
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php -r "unlink('composer-setup.php');"

# Initialize a new project
composer init

# Install a package
composer require guzzlehttp/guzzle
composer require vlucas/phpdotenv

# Install dev-only packages
composer require --dev phpunit/phpunit
composer require --dev phpstan/phpstan

# Install from composer.json
composer install

# Update packages
composer update

composer.json Configuration

{
    "name": "myapp/web-project",
    "description": "A PHP web application",
    "type": "project",
    "require": {
        "php": ">=8.1",
        "guzzlehttp/guzzle": "^7.0",
        "vlucas/phpdotenv": "^5.5",
        "monolog/monolog": "^3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "phpstan/phpstan": "^1.0"
    },
    "autoload": {
        "psr-4": {
            "App\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\": "tests/"
        }
    },
    "scripts": {
        "test": "phpunit",
        "analyse": "phpstan analyse src",
        "start": "php -S localhost:8000 -t public"
    }
}

PSR-4 Autoloading

<?php
// src/Models/User.php
namespace App\Models;

class User {
    public function __construct(
        private readonly int $id,
        private readonly string $name,
        private readonly string $email
    ) {}

    public function getName(): string { return $this->name; }
    public function getEmail(): string { return $this->email; }
}

// src/Services/UserService.php
namespace App\Services;

use App\Models\User;

class UserService {
    public function createUser(string $name, string $email): User {
        return new User(0, $name, $email);
    }
}

// public/index.php (entry point)
require_once __DIR__ . '/../vendor/autoload.php';

use App\Services\UserService;
use Dotenv\Dotenv;

// Load environment variables
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();

$service = new UserService();
$user = $service->createUser('Alice', 'alice@example.com');
echo $user->getName();
?>

Project Structure

# Standard PHP project layout
my-project/
├── composer.json
├── composer.lock
├── .env                 # Environment variables (never commit)
├── .gitignore
├── public/              # Web root (only this is accessible via web)
│   ├── index.php        # Entry point
│   └── assets/
│       ├── css/
│       └── js/
├── src/                 # Application code (PSR-4: App\)
│   ├── Controllers/
│   ├── Models/
│   ├── Services/
│   └── Middleware/
├── config/              # Configuration files
├── templates/           # View templates
├── tests/               # Test files (PSR-4: Tests\)
├── storage/             # Logs, cache, uploads
│   ├── logs/
│   └── cache/
└── vendor/              # Composer dependencies (never commit)
Pro tip: Always commit composer.lock to version control — it ensures every developer and server installs the exact same versions of dependencies. Use composer install (not composer update) in production and CI environments to get reproducible builds. Never commit the vendor/ directory.

Key Takeaways

  • Composer manages PHP dependencies with composer.json (requirements) and composer.lock (exact versions).
  • PSR-4 autoloading maps namespaces to directories, eliminating manual require statements.
  • Use require for production dependencies and require --dev for development tools.
  • Always commit composer.lock and never commit vendor/ to version control.
  • Use Composer scripts for common tasks: composer test, composer start, etc.