08: Composer & Dependencies

Chapter 8: Composer & Dependencies
Section titled “Chapter 8: Composer & Dependencies”Overview
Section titled “Overview”Composer is PHP’s dependency manager—think Maven or Gradle for Java. It handles package installation, autoloading, version management, and dependency resolution. Modern PHP development is unthinkable without Composer. In this chapter, you’ll learn everything you need to master dependency management in PHP.
Prerequisites
Section titled “Prerequisites”::: info Time Estimate ⏱️ 75-90 minutes to complete this chapter :::
What you need:
- Completed Chapter 7: Error Handling
- Understanding of Java dependency management (Maven/Gradle)
- Command line familiarity
What You’ll Build
Section titled “What You’ll Build”In this chapter, you’ll:
- Set up a complete Composer project from scratch
- Manage dependencies with version constraints
- Create publishable packages
- Configure advanced autoloading
- Build reproducible deployments
Learning Objectives
Section titled “Learning Objectives”By the end of this chapter, you’ll be able to:
- Install and configure Composer
- Manage dependencies with composer.json
- Understand version constraints and semantic versioning
- Use autoloading (PSR-4, classmap, files)
- Work with lock files for reproducible builds
- Create and publish packages
- Compare Composer to Maven/Gradle
- Use common packages from the PHP ecosystem
Section 1: Introduction to Composer
Section titled “Section 1: Introduction to Composer”Understand what Composer is and how it compares to Java build tools.
What is Composer?
Section titled “What is Composer?”Composer is two things:
- Dependency Manager: Downloads and manages third-party libraries
- Autoloader Generator: Creates optimized class autoloading
::: code-group
{ "name": "mycompany/myapp", "require": { "php": ">=8.3", "monolog/monolog": "^3.0", "guzzlehttp/guzzle": "^7.8" }, "autoload": { "psr-4": { "App\\": "src/" } }}<project> <groupId>com.mycompany</groupId> <artifactId>myapp</artifactId> <version>1.0.0</version>
<properties> <maven.compiler.source>17</maven.compiler.source> </properties>
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.12.0</version> </dependency> </dependencies></project>plugins { id 'java'}
group = 'com.mycompany'version = '1.0.0'
java { sourceCompatibility = JavaVersion.VERSION_17}
dependencies { implementation 'org.apache.logging.log4j:log4j-core:2.20.0' implementation 'com.squareup.okhttp3:okhttp:4.12.0'}:::
Composer vs Maven/Gradle
Section titled “Composer vs Maven/Gradle”| Feature | Composer | Maven | Gradle |
|---|---|---|---|
| Configuration | composer.json | pom.xml | build.gradle |
| Lock file | composer.lock | N/A (uses ranges) | gradle.lock |
| Repository | Packagist.org | Maven Central | Maven Central + more |
| Scope | Dependencies + Autoloading | Full build lifecycle | Full build lifecycle |
| Speed | Fast | Slow | Fast |
| Build tasks | Limited (scripts only) | Extensive (phases) | Extensive (tasks) |
::: tip Key Difference Composer focuses on dependency management and autoloading, not full build lifecycle. For build tasks, PHP developers use separate tools (PHPUnit, PHPStan, etc.) or build scripts. :::
Section 2: Installing and Configuring Composer
Section titled “Section 2: Installing and Configuring Composer”Install Composer and set up your first project.
Installation
Section titled “Installation”::: code-group
# Download installerphp -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
# Verify installer (optional but recommended)php -r "if (hash_file('sha384', 'composer-setup.php') === file_get_contents('https://composer.github.io/installer.sig')) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
# Install globallyphp composer-setup.php --install-dir=/usr/local/bin --filename=composer
# Cleanupphp -r "unlink('composer-setup.php');"
# Verify installationcomposer --version# Download and run Composer-Setup.exe from https://getcomposer.org/download/
# Or via PowerShell:php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"php composer-setup.php --install-dir=bin --filename=composer.batphp -r "unlink('composer-setup.php');"
# Verifycomposer --version# Use official Composer imagedocker run --rm -v $(pwd):/app composer:latest install
# Or add to DockerfileFROM php:8.3-cliCOPY --from=composer:latest /usr/bin/composer /usr/bin/composer:::
Creating Your First Project
Section titled “Creating Your First Project”# Create a new directorymkdir my-php-app && cd my-php-app
# Initialize composer.json interactivelycomposer init
# Or create manuallycat > composer.json <<'EOF'{ "name": "mycompany/my-app", "description": "My PHP Application", "type": "project", "require": { "php": ">=8.3" }, "autoload": { "psr-4": { "App\\": "src/" } }}EOF
# Install dependencies (creates vendor/ directory)composer installDirectory Structure After Installation
Section titled “Directory Structure After Installation”my-php-app/├── composer.json # Dependencies and configuration├── composer.lock # Locked versions (commit this!)├── vendor/ # Downloaded packages (don't commit)│ ├── autoload.php # Include this in your application│ ├── composer/ # Composer-generated files│ └── ... # Installed packages└── src/ # Your application code └── ...::: warning Important
- DO commit: composer.json, composer.lock
- DON’T commit: vendor/ directory
- Add
vendor/to.gitignore:::
Section 3: composer.json Deep Dive
Section titled “Section 3: composer.json Deep Dive”Master the composer.json configuration file.
Complete composer.json Example
Section titled “Complete composer.json Example”{ "name": "mycompany/my-app", "description": "A sample PHP application", "type": "project", "license": "MIT", "authors": [ { "name": "John Doe", "email": "john@example.com", "homepage": "https://example.com", "role": "Developer" } ], "require": { "php": ">=8.3", "ext-pdo": "*", "ext-json": "*", "monolog/monolog": "^3.0", "guzzlehttp/guzzle": "^7.8" }, "require-dev": { "phpunit/phpunit": "^10.5", "phpstan/phpstan": "^1.10" }, "autoload": { "psr-4": { "App\\": "src/", "Database\\": "database/" }, "classmap": ["legacy/"], "files": ["helpers/functions.php"] }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }, "scripts": { "test": "phpunit", "analyse": "phpstan analyse src", "post-install-cmd": [ "@php artisan optimize" ] }, "config": { "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true, "allow-plugins": { "php-http/discovery": true } }, "minimum-stability": "stable", "prefer-stable": true}Key Sections Explained
Section titled “Key Sections Explained”1. Package Information
{ "name": "vendor/package", // Required for libraries, optional for projects "description": "...", // Short description "type": "project", // project, library, metapackage, etc. "license": "MIT" // SPDX license identifier}2. Dependencies
{ "require": { "php": ">=8.3", // PHP version constraint "ext-pdo": "*", // PHP extension requirement "monolog/monolog": "^3.0" // Package with version constraint }, "require-dev": { "phpunit/phpunit": "^10.5" // Development-only dependencies }}3. Autoloading
{ "autoload": { "psr-4": { "App\\": "src/" // PSR-4 namespace mapping }, "classmap": ["legacy/"], // Scan directories for classes "files": ["helpers.php"] // Always include these files }}4. Scripts
{ "scripts": { "test": "phpunit", // Custom command "post-install-cmd": [ // Hook after composer install "@php artisan optimize" ] }}Section 4: Managing Dependencies
Section titled “Section 4: Managing Dependencies”Learn to add, update, and remove packages.
Adding Dependencies
Section titled “Adding Dependencies”# Add production dependencycomposer require monolog/monolog
# Add with specific versioncomposer require monolog/monolog:^3.0
# Add multiple packagescomposer require guzzlehttp/guzzle symfony/http-foundation
# Add development dependencycomposer require --dev phpunit/phpunit
# Add with constraintcomposer require "symfony/console:^6.4"Updating Dependencies
Section titled “Updating Dependencies”# Update all packagescomposer update
# Update specific packagecomposer update monolog/monolog
# Update multiple packagescomposer update monolog/monolog guzzlehttp/guzzle
# Update without updating dependenciescomposer update --no-dependencies monolog/monolog
# Dry run (see what would be updated)composer update --dry-run
# Update with platform requirementscomposer update --with-all-dependenciesRemoving Dependencies
Section titled “Removing Dependencies”# Remove packagecomposer remove monolog/monolog
# Remove dev packagecomposer remove --dev phpunit/phpunit
# Remove multiple packagescomposer remove package1 package2Searching and Inspecting
Section titled “Searching and Inspecting”# Search for packagescomposer search monolog
# Show package informationcomposer show monolog/monolog
# Show all installed packagescomposer show
# Show installed packages treecomposer show --tree
# Show outdated packagescomposer outdated
# Show why package is installedcomposer depends monolog/monolog
# Show what packages depend on thiscomposer prohibits php:8.4Section 5: Version Constraints & Semantic Versioning
Section titled “Section 5: Version Constraints & Semantic Versioning”Master version constraints for reliable dependency management.
Semantic Versioning (SemVer)
Section titled “Semantic Versioning (SemVer)”PHP packages follow semantic versioning: MAJOR.MINOR.PATCH
- MAJOR: Breaking changes (incompatible API changes)
- MINOR: New features (backward-compatible)
- PATCH: Bug fixes (backward-compatible)
Example: 3.5.2
- Major: 3
- Minor: 5
- Patch: 2
Version Constraint Operators
Section titled “Version Constraint Operators”::: code-group
{ "require": { "vendor/package": "1.2.3" // Only 1.2.3 (not recommended) }}{ "require": { // Allows: 1.2.3, 1.2.4, 1.3.0, 1.9.9 // Blocks: 2.0.0 (breaking changes) "vendor/package": "^1.2.3" }}// ^ allows changes that don't modify left-most non-zero digit{ "require": { // Allows: 1.2.3, 1.2.4, 1.2.99 // Blocks: 1.3.0 (new features) "vendor/package": "~1.2.3" }}// ~ allows last digit to increment{ "require": { // Allows: 1.2.0, 1.2.1, 1.2.99 // Blocks: 1.3.0 "vendor/package": "1.2.*" }}{ "require": { // Allows versions between 1.2 and 2.0 (exclusive) "vendor/package": ">=1.2 <2.0" }}{ "require": { // Allows either range "vendor/package": "^1.2 || ^2.0" }}:::
Version Constraint Comparison
Section titled “Version Constraint Comparison”| Constraint | 1.2.3 | 1.2.4 | 1.3.0 | 2.0.0 | Use Case |
|---|---|---|---|---|---|
1.2.3 | ✅ | ❌ | ❌ | ❌ | Exact version (avoid) |
^1.2.3 | ✅ | ✅ | ✅ | ❌ | Recommended (safe updates) |
~1.2.3 | ✅ | ✅ | ❌ | ❌ | Conservative (patch only) |
1.2.* | ✅ | ✅ | ❌ | ❌ | Wildcard (patch only) |
>=1.2.3 | ✅ | ✅ | ✅ | ✅ | Range (risky) |
Java Comparison
Section titled “Java Comparison”::: code-group
{ "require": { "monolog/monolog": "^3.0" }}<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>[2.0,3.0)</version></dependency>dependencies { implementation 'org.apache.logging.log4j:log4j-core:2.+'}:::
::: tip Best Practice
- Production: Use
^(caret) for safe automatic updates - Library: Use
^for maximum compatibility - Development: Use
*or^for latest features - Avoid: Exact versions unless you have a specific reason :::
Section 6: Lock Files & Reproducible Builds
Section titled “Section 6: Lock Files & Reproducible Builds”Understand composer.lock and ensure reproducible deployments.
What is composer.lock?
Section titled “What is composer.lock?”When you run composer install, Composer:
- Reads
composer.jsonfor dependencies - Resolves exact versions satisfying constraints
- Writes exact versions to
composer.lock - Downloads and installs packages
composer.lock Example
Section titled “composer.lock Example”{ "_readme": [ "This file locks the dependencies to known versions", "Always commit this file to version control" ], "content-hash": "a5c8d5f3d8b4e6f1a2c3d4e5f6a7b8c9", "packages": [ { "name": "monolog/monolog", "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", "reference": "abc123..." }, "require": { "php": ">=8.1" }, "time": "2024-01-15T10:30:45+00:00" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { "php": ">=8.3" }}Install vs Update
Section titled “Install vs Update”# composer install# - Reads composer.lock (if exists)# - Installs exact versions from lock file# - Creates lock file if missing# Use: CI/CD, production deployment, new developer setup
composer install
# composer update# - Ignores composer.lock# - Resolves latest versions from composer.json constraints# - Updates composer.lock with new versions# Use: When you want to update dependencies
composer updateWorkflow
Section titled “Workflow”::: code-group
# Add new dependencycomposer require guzzlehttp/guzzle
# This updates both:# - composer.json (adds package)# - composer.lock (locks version)
# Commit both filesgit add composer.json composer.lockgit commit -m "Add Guzzle HTTP client"git push# Pull latest code (includes composer.lock)git pull
# Install exact versions from lock filecomposer install --no-dev --optimize-autoloader
# Run tests, build, deploy...# Pull latest codegit pull
# Install dependencies (uses composer.lock)composer install
# Now has exact same package versions!:::
Best Practices
Section titled “Best Practices”::: tip Lock File Guidelines
DO:
- ✅ Commit
composer.lockto version control - ✅ Run
composer installin CI/CD - ✅ Run
composer installwhen pulling code - ✅ Run
composer updatedeliberately - ✅ Review lock file changes in PRs
DON’T:
- ❌ Add
composer.lockto.gitignore(for applications) - ❌ Run
composer updatein production - ❌ Manually edit
composer.lock - ❌ Ignore lock file conflicts :::
Java Comparison
Section titled “Java Comparison”| Tool | PHP | Java (Maven) | Java (Gradle) |
|---|---|---|---|
| Manifest | composer.json | pom.xml | build.gradle |
| Lock file | composer.lock | N/A | gradle.lockfile |
| Install | composer install | mvn install | gradle build |
| Update | composer update | mvn versions:use-latest-versions | gradle dependencies --write-locks |
Section 7: Autoloading Strategies
Section titled “Section 7: Autoloading Strategies”Master all autoloading strategies in Composer.
PSR-4 Autoloading (Recommended)
Section titled “PSR-4 Autoloading (Recommended)”{ "autoload": { "psr-4": { "App\\": "src/", "App\\Controllers\\": "app/Controllers/", "Domain\\": "src/Domain/" } }}Mapping:
App\Models\User→src/Models/User.phpApp\Controllers\UserController→app/Controllers/UserController.phpDomain\User\Entity→src/Domain/User/Entity.php
Classmap Autoloading
Section titled “Classmap Autoloading”For legacy code or non-PSR-4 structure:
{ "autoload": { "classmap": [ "legacy/", "lib/OldClasses", "database/seeds", "database/factories" ] }}After changing classmap, regenerate:
composer dump-autoloadFiles Autoloading
Section titled “Files Autoloading”For helper functions and constants:
{ "autoload": { "files": [ "helpers/functions.php", "config/constants.php" ] }}helpers/functions.php:
<?php
declare(strict_types=1);
if (!function_exists('env')) { function env(string $key, mixed $default = null): mixed { return $_ENV[$key] ?? $default; }}
if (!function_exists('config')) { function config(string $key, mixed $default = null): mixed { // Load configuration return $default; }}Combined Example
Section titled “Combined Example”{ "autoload": { "psr-4": { "App\\": "src/", "Database\\": "database/" }, "classmap": [ "legacy/" ], "files": [ "helpers/functions.php" ] }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }}Optimization
Section titled “Optimization”# Development: Fast, allows file changescomposer dump-autoload
# Production: Optimized classmapcomposer dump-autoload --optimize
# Production: Authoritative (fastest)composer dump-autoload --classmap-authoritative
# Production: With APCu cachingcomposer dump-autoload --apcuSection 8: Scripts and Hooks
Section titled “Section 8: Scripts and Hooks”Automate tasks with Composer scripts.
Defining Scripts
Section titled “Defining Scripts”{ "scripts": { "test": "phpunit", "test:unit": "phpunit --testsuite=unit", "test:integration": "phpunit --testsuite=integration", "analyse": "phpstan analyse src", "format": "php-cs-fixer fix", "check": [ "@test", "@analyse" ] }}Running scripts:
composer testcomposer analysecomposer check # Runs multiple commandsEvent Hooks
Section titled “Event Hooks”Composer provides hooks for various events:
{ "scripts": { "pre-install-cmd": [ "echo 'Before composer install'" ], "post-install-cmd": [ "@php artisan cache:clear", "@php artisan config:cache" ], "pre-update-cmd": [ "echo 'Before composer update'" ], "post-update-cmd": [ "@php artisan migrate" ], "post-autoload-dump": [ "@php artisan package:discover" ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "@php artisan key:generate" ] }}Advanced Script Features
Section titled “Advanced Script Features”{ "scripts": { "build": [ "Composer\\Config::disableProcessTimeout", // Disable timeout "@php build.php" ], "deploy": { "script": "deploy.sh", "timeout": 600 // 10 minutes } }, "scripts-descriptions": { "test": "Run the full test suite", "build": "Build production assets", "deploy": "Deploy to production" }}Script variables:
# Access composer variables in scriptscomposer run-script --list # List all scriptsSection 9: Private Packages & Repositories
Section titled “Section 9: Private Packages & Repositories”Learn to use private packages and custom repositories.
Private Repository Configuration
Section titled “Private Repository Configuration”{ "repositories": [ { "type": "vcs", "url": "https://github.com/mycompany/private-package.git" }, { "type": "composer", "url": "https://repo.example.com" }, { "type": "path", "url": "../packages/my-local-package" } ], "require": { "mycompany/private-package": "^1.0" }}Repository Types
Section titled “Repository Types”1. VCS Repository (Git)
{ "repositories": [ { "type": "vcs", "url": "git@github.com:mycompany/private-lib.git" } ]}Requires authentication:
# GitHub tokencomposer config github-oauth.github.com YOUR_TOKEN
# GitLab tokencomposer config gitlab-oauth.gitlab.com YOUR_TOKEN2. Private Packagist
{ "repositories": [ { "type": "composer", "url": "https://repo.packagist.com/mycompany/" } ], "config": { "http-basic": { "repo.packagist.com": { "username": "token", "password": "YOUR_PACKAGIST_TOKEN" } } }}3. Local Path Repository (Monorepo)
{ "repositories": [ { "type": "path", "url": "./packages/*", "options": { "symlink": true } } ], "require": { "mycompany/package-one": "^1.0", "mycompany/package-two": "^1.0" }}Authentication
Section titled “Authentication”auth.json (don’t commit!):
{ "http-basic": { "repo.example.com": { "username": "myuser", "password": "mypassword" } }, "github-oauth": { "github.com": "ghp_xxxxxxxxxxxxxxxxxxxx" }, "gitlab-oauth": { "gitlab.com": "glpat-xxxxxxxxxxxxxxxxxxxx" }}Environment variables:
export COMPOSER_AUTH='{"github-oauth":{"github.com":"TOKEN"}}'composer installSection 10: Common Packages & Ecosystem
Section titled “Section 10: Common Packages & Ecosystem”Discover essential packages every PHP developer should know.
Essential Packages by Category
Section titled “Essential Packages by Category”1. Logging
composer require monolog/monolog<?php
use Monolog\Logger;use Monolog\Handler\StreamHandler;
$log = new Logger('app');$log->pushHandler(new StreamHandler('app.log', Logger::INFO));
$log->info('User logged in', ['user_id' => 42]);$log->error('Database connection failed', ['error' => $e->getMessage()]);2. HTTP Client
composer require guzzlehttp/guzzle<?php
use GuzzleHttp\Client;
$client = new Client();$response = $client->get('https://api.example.com/users');
$data = json_decode($response->getBody(), true);3. Testing
composer require --dev phpunit/phpunitcomposer require --dev mockery/mockery4. Static Analysis
composer require --dev phpstan/phpstancomposer require --dev vimeo/psalm5. Code Quality
composer require --dev friendsofphp/php-cs-fixercomposer require --dev squizlabs/php_codesniffer6. Date/Time
composer require nesbot/carbon<?php
use Carbon\Carbon;
$now = Carbon::now();$tomorrow = $now->addDay();$formatted = $now->format('Y-m-d H:i:s');$human = $now->diffForHumans(); // "2 minutes ago"7. Collections
composer require illuminate/collections<?php
use Illuminate\Support\Collection;
$collection = collect([1, 2, 3, 4, 5]) ->filter(fn($n) => $n > 2) ->map(fn($n) => $n * 2) ->sum(); // 248. Validation
composer require respect/validation9. Database (ORM)
composer require illuminate/database # Laravel Eloquent# orcomposer require doctrine/orm # Doctrine10. Environment Variables
composer require vlucas/phpdotenv<?php
use Dotenv\Dotenv;
$dotenv = Dotenv::createImmutable(__DIR__);$dotenv->load();
$dbHost = $_ENV['DB_HOST'];Framework Ecosystems
Section titled “Framework Ecosystems”Laravel:
composer create-project laravel/laravel my-appSymfony:
composer create-project symfony/skeleton my-appSlim (Microframework):
composer require slim/slim slim/psr7Section 11: Practical Example - Complete Project Setup
Section titled “Section 11: Practical Example - Complete Project Setup”Build a complete project with dependencies, autoloading, and scripts.
Project: User Management API
Section titled “Project: User Management API”1. Initialize project
mkdir user-api && cd user-apicomposer init --name="mycompany/user-api" --no-interaction2. Complete composer.json
{ "name": "mycompany/user-api", "description": "User Management REST API", "type": "project", "license": "MIT", "require": { "php": ">=8.3", "ext-pdo": "*", "ext-json": "*", "monolog/monolog": "^3.0", "guzzlehttp/guzzle": "^7.8", "vlucas/phpdotenv": "^5.6", "respect/validation": "^2.3" }, "require-dev": { "phpunit/phpunit": "^10.5", "phpstan/phpstan": "^1.10", "friendsofphp/php-cs-fixer": "^3.47" }, "autoload": { "psr-4": { "App\\": "src/" }, "files": [ "helpers/functions.php" ] }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } }, "scripts": { "test": "phpunit", "analyse": "phpstan analyse src --level=9", "format": "php-cs-fixer fix", "check": [ "@test", "@analyse" ], "serve": "php -S localhost:8000 -t public" }, "config": { "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true }, "minimum-stability": "stable", "prefer-stable": true}3. Install dependencies
composer install4. Directory structure
user-api/├── composer.json├── composer.lock├── vendor/├── src/│ ├── Controllers/│ │ └── UserController.php│ ├── Models/│ │ └── User.php│ ├── Services/│ │ └── UserService.php│ └── Database/│ └── Connection.php├── public/│ └── index.php├── helpers/│ └── functions.php├── tests/│ └── UserServiceTest.php├── .env.example└── .gitignore5. Application code
<?phpdeclare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use Dotenv\Dotenv;use App\Controllers\UserController;use App\Services\UserService;use App\Database\Connection;use Monolog\Logger;use Monolog\Handler\StreamHandler;
// Load environment$dotenv = Dotenv::createImmutable(__DIR__ . '/..');$dotenv->load();
// Setup logging$log = new Logger('api');$log->pushHandler(new StreamHandler('logs/app.log', Logger::INFO));
// Database connection$db = Connection::make([ 'host' => env('DB_HOST', 'localhost'), 'database' => env('DB_NAME'), 'username' => env('DB_USER'), 'password' => env('DB_PASS'),]);
// Services$userService = new UserService($db, $log);$controller = new UserController($userService);
// Route handling$method = $_SERVER['REQUEST_METHOD'];$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
match ([$method, $path]) { ['GET', '/users'] => $controller->index(), ['GET', '/users/{id}'] => $controller->show($_GET['id']), ['POST', '/users'] => $controller->store($_POST), default => http_response_code(404),};6. Run the application
composer serve# Visit: http://localhost:80007. Run quality checks
# Run testscomposer test
# Static analysiscomposer analyse
# Format codecomposer format
# Run all checkscomposer checkExercises
Section titled “Exercises”Exercise 1: Create a Library Package
Section titled “Exercise 1: Create a Library Package”Create a reusable library package:
Requirements:
- Package name:
yourname/string-helper - PSR-4 autoloading
- Unit tests with PHPUnit
- Publish to Packagist.org
Exercise 2: Monorepo Setup
Section titled “Exercise 2: Monorepo Setup”Create a monorepo with multiple packages:
Requirements:
- Root composer.json with path repositories
- Three packages: core, api, web
- api and web depend on core
- Demonstrate cross-package usage
Exercise 3: Custom Scripts
Section titled “Exercise 3: Custom Scripts”Set up a project with comprehensive scripts:
Requirements:
- test, test:unit, test:integration scripts
- analyse (PHPStan), format (CS Fixer) scripts
- pre/post install hooks
- Custom deployment script
Wrap-up Checklist
Section titled “Wrap-up Checklist”Before moving to the next chapter, ensure you can:
- Install and configure Composer
- Create and configure composer.json
- Manage dependencies (add, update, remove)
- Understand version constraints and semantic versioning
- Use composer.lock for reproducible builds
- Configure PSR-4, classmap, and files autoloading
- Create and use scripts and hooks
- Set up private repositories
- Use common packages from the ecosystem
- Compare Composer to Maven/Gradle
- Build complete projects with Composer
::: tip Ready for More? In Chapter 9: Working with Arrays, we’ll explore PHP’s powerful array manipulation functions and how they compare to Java Streams. :::
Further Reading
Section titled “Further Reading”Official Documentation:
- Composer Documentation
- Packagist.org - Package repository
- PSR-4 Autoloading
Tools:
- Private Packagist - Private package hosting
- Composer Plugin API