Small PHP projects start with a few files joined together by require. As the project grows, that approach struggles. You end up with long lists of require_once lines at the top of every file, and sooner or later two pieces of code both want a class called User or a function called format().
Modern PHP solves both problems. Namespaces give every class a full name, like a folder path, so App\Models\User and Vendor\Auth\User can live side by side. Autoloading loads each class file automatically the first time it's used, so the require lists disappear.
Composer, PHP's package manager, ties it together. It sets up autoloading for your own code and downloads thousands of well-tested libraries, for sending email, handling dates, reading spreadsheets or building whole websites, with a single command. Every modern PHP framework is installed and run through Composer.
Namespaces
Declare a namespace at the very top of a file, after <?php:
<?php
namespace App\Models;
class User { /* ... */ }The class's full name is now App\Models\User. Namespaces use backslashes and usually match the folder structure: src/Models/User.php. Built-in classes such as DateTimeImmutable and PDO live in the global namespace; inside a namespaced file, write them with a leading backslash, \PDO, or import them with use.
use and aliases
use imports a class so you can refer to it by its short name:
use App\Models\User;
use App\Services\Mailer as AppMailer;
use DateTimeImmutable;
$user = new User();
$mailer = new AppMailer();usestatements go after the namespace line and before any code.asgives an alias, useful when two imported classes share a short name.useonly creates a shortcut; it doesn't load the file. Loading is autoloading's job.
Composer and PSR-4 autoloading
Install Composer from getcomposer.org, then in your project folder run composer init, or create composer.json yourself:
{
"autoload": {
"psr-4": { "App\\": "src/" }
}
}This PSR-4 rule says: classes whose names start with App\ live in the src folder, with the rest of the name as the path. So App\Models\User is loaded from src/Models/User.php. Run composer dump-autoload, then put one line at the start of your entry file, such as index.php:
require __DIR__ . '/vendor/autoload.php';From then on, every class loads itself the first time it's used.
Installing packages
composer require downloads a package and everything it depends on into the vendor folder, and records it in composer.json:
| Command | Does |
|---|---|
composer require vlucas/phpdotenv | Add a package |
composer require --dev phpunit/phpunit | Add a package only needed for development |
composer install | Install exactly the versions in composer.lock |
composer update | Update packages within the allowed versions |
composer outdated | List packages with newer versions |
Packages are listed on packagist.org. Commit composer.json and composer.lock to Git, but add vendor/ to .gitignore: anyone can rebuild it with composer install.
PHP Composer Syntax
Namespaces and Composer
<?php
namespace App\Services;
use App\Models\User;
use DateTimeImmutable as Date;
require __DIR__ . '/../vendor/autoload.php';composer init
composer require vendor/package
composer require --dev phpunit/phpunit
composer install
composer dump-autoloadPHP Composer Summary
- A namespace gives classes a full name like App\Models\User, avoiding clashes.
useimports a class by its short name, withasfor aliases; built-in classes are in the global namespace.- PSR-4 in composer.json maps a namespace prefix to a folder; one class per file.
require 'vendor/autoload.php'once, and classes load automatically.composer requireadds packages; commit composer.json and composer.lock, not vendor/.
PHP Composer Examples
Each example shows the code, the output it produces and what each part does.
A small project with namespaces
my-shop/
composer.json
public/index.php
src/Models/Product.php
src/Services/PriceFormatter.php
vendor/ (created by Composer)<?php
// src/Models/Product.php
namespace App\Models;
class Product {
public function __construct(
public readonly string $name,
public readonly float $price,
) {}
}<?php
// src/Services/PriceFormatter.php
namespace App\Services;
use App\Models\Product;
class PriceFormatter {
public function format(Product $p): string {
return $p->name . ": £" . number_format($p->price, 2);
}
}App\Models\Product -> src/Models/Product.php
App\Services\PriceFormatter -> src/Services/PriceFormatter.phpLine-by-line explanation
- Line 3In both files, the namespace matches the folder:
App\Modelsissrc/ModelsandApp\Servicesissrc/Services. - Line 5In Product.php, the class name matches the file name exactly. In PriceFormatter.php, line 5 imports Product so its short name works.
The entry file and the autoloader
<?php
// public/index.php
require __DIR__ . '/../vendor/autoload.php';
use App\Models\Product;
use App\Services\PriceFormatter;
$items = [new Product('Backpack', 34.99), new Product('Pen', 1.2)];
$formatter = new PriceFormatter();
foreach ($items as $item) {
echo $formatter->format($item) . "\n";
}
echo get_class($formatter) . "\n";Backpack: £34.99
Pen: £1.20
App\Services\PriceFormatterLine-by-line explanation
- Line 3The one and only require: Composer's autoloader.
- Lines 5 to 6Import the classes by their full names.
- Lines 8 to 9The first time Product and PriceFormatter are used, the autoloader finds and loads their files.
- Line 14get_class shows the full, namespaced name.
Installing and using a package
composer require nesbot/carbon<?php
require __DIR__ . '/vendor/autoload.php';
use Carbon\CarbonImmutable;
$posted = CarbonImmutable::parse('2024-07-01 09:00');
$now = CarbonImmutable::parse('2024-07-05 09:00');
echo "Posted " . $posted->diffForHumans($now) . "\n";
echo "Deadline: " . $now->addWeekdays(3)->format('l j F') . "\n";Using version ^3.8 for nesbot/carbon
./composer.json has been updated
Package operations: 4 installs, 0 updates, 0 removals
Generating autoload files
Posted 4 days before
Deadline: Wednesday 10 JulyLine-by-line explanation
- Line 1composer require downloads Carbon, a popular date library, plus its dependencies. Your version numbers may differ.
- Line 4The package's classes live in its own namespace, Carbon.
- Lines 8 to 9Ready-made helpers like diffForHumans save writing your own date code.
Common PHP Composer Mistakes
Code before the namespace
<?php
echo "Loading";
namespace App\Models; // Fatal error: namespace must come first<?php
namespace App\Models;Built-in classes inside a namespace
namespace App\Services;
$pdo = new PDO($dsn); // looks for App\Services\PDOnamespace App\Services;
use PDO;
$pdo = new PDO($dsn);Committing the vendor folder
git add vendor/ # thousands of files that Composer can rebuild# .gitignore
/vendor/
# commit composer.json and composer.lock insteadPHP Composer in Real Projects
Composer in the PHP world
Laravel, Symfony, WordPress plugins and nearly every modern PHP library are installed with Composer, and Packagist hosts hundreds of thousands of packages. Hosting platforms run composer install --no-dev when deploying, so production servers get exactly the tested versions recorded in composer.lock, without the development tools.
PHP Composer FAQ
What is the difference between composer install and composer update?
composer install installs the exact versions recorded in composer.lock, so everyone on the project and the production server gets identical packages. composer update looks for newer versions allowed by composer.json, installs them and rewrites the lock file. Run update deliberately, review the changes and commit the new lock file.
Why does PHP say "Class not found" with Composer?
Check four things: the entry file requires vendor/autoload.php; the namespace matches the PSR-4 prefix in composer.json; the folder and file names match the namespace and class name exactly, including capital letters; and you ran composer dump-autoload after changing the autoload settings.
How do I use a function or constant from another namespace?
Import it with use function or use const: use function App\Helpers\formatPrice; lets you call formatPrice() directly. Without an import, write the fully qualified name with a leading backslash, \App\Helpers\formatPrice(). Composer's files autoload setting loads files of functions, since PSR-4 only covers classes.
Do I need Composer for a small PHP project?
Not strictly, but it quickly pays off. Even with no packages, Composer's autoloader removes require lists, and as soon as you need a library, such as a mailer or a PDF generator, it handles downloading, versions and dependencies for you.
Should vendor be uploaded to the server?
Not by copying it from your computer. Deploy composer.json and composer.lock, then run composer install --no-dev --optimize-autoloader on the server or in your build pipeline. That installs exactly the locked versions without development tools and builds a faster autoloader.
PHP Composer Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the line that loads Composer's autoloader.
require __DIR__ . '/vendor/';
What is a namespace for?
With PSR-4 mapping "App\\" to "src/", where does App\Services\Mailer live?
Which command adds a package needed only during development?
Why commit composer.lock?
PHP Composer Quiz
5 questions to check what you learned.
Which keyword imports a class by its short name?
- use
- import
- require
- include
Where must the namespace declaration go?
- Anywhere in the file
- At the top of the file, before any other code
- At the end of the file
- Inside the class
Should the vendor folder be committed to Git?
- No, it's rebuilt with composer install
- Yes, always
- Only the autoload.php file
- Only on Windows
What does
use App\Services\Mailer as AppMailer;do?- Renames the file
- Creates a new class
- Imports the class under the alias AppMailer
- Loads the file immediately
What does autoloading do?
- Loads every class when the app starts
- Updates packages
- Compiles PHP code
- Loads a class's file automatically the first time the class is used