A big part of using Composer is deciding which versions you accept. Most PHP packages follow semantic versioning (semver):
MAJOR.MINOR.PATCH for example 2.10.3
| Part | Changes when | Safe to upgrade? |
|---|---|---|
| PATCH (2.10.3) | Bug fixes | Yes |
| MINOR (2.10.3) | New features, still compatible | Yes |
| MAJOR (2.10.3) | Breaking changes | Read the upgrade guide |
Version constraints
| Constraint | Means | Accepts |
|---|---|---|
2.10.3 | Exactly this version | 2.10.3 only |
^2.10 | The caret: compatible with 2.10 | 2.10.0 up to, not including, 3.0.0 |
~2.10 | The tilde: this minor line | 2.10.0 up to, not including, 3.0.0 |
~2.10.3 | 2.10.3 up to, not including, 2.11.0 | |
2.* | Wildcard | Any 2.x version |
>=2.0 <3.0 | A range | Same as ^2.0 |
dev-main | A branch | The latest code on that branch (avoid in apps) |
^ is what Composer writes for you with composer require. It is the right default: you get fixes and new features, but not breaking changes.
A tiny constraint checker
This function shows what ^2.10 means.
<?php
function matchesCaret(string $version, string $constraint): bool
{
[$major, $minor] = array_map("intval", explode(".", ltrim($constraint, "^")));
[$vMajor, $vMinor] = array_map("intval", explode(".", $version));
return $vMajor === $major && $vMinor >= $minor;
}
var_dump(matchesCaret("2.10.3", "^2.10"));
var_dump(matchesCaret("2.9.0", "^2.10"));
var_dump(matchesCaret("3.0.0", "^2.10"));
bool(true)
bool(false)
bool(false)
Why constraints matter
- Too loose (
*): an update can break your app. - Too strict (
2.10.3): you never get security fixes. ^is the sweet spot.
require vs require-dev
require: needed in production.require-dev: tests, linters, debug bars. Not installed with--no-dev.
Platform requirements
{
"require": {
"php": "^8.2",
"ext-json": "*",
"ext-mbstring": "*"
}
}
Composer checks that your PHP version and extensions match. The config.platform setting can pretend you have a certain PHP version, which is handy when you develop on a newer PHP than your production server runs.
Inspect your dependencies
composer show # all installed packages
composer show --tree # the dependency tree
composer why vendor/pkg # why a package is installed
composer outdated # what could be updated
composer audit # known security problems
Keeping dependencies healthy
- Install only what you need. Every package is code you must trust and maintain.
- Prefer maintained packages. Check release dates and open issues.
- Update regularly, in small steps.
- Read changelogs for major versions.
- Run tests after every update.
- Run
composer auditin your build.
Licences
Each package has a licence (MIT, GPL and so on). For commercial projects, make sure the licences fit how you use the code. composer licenses lists them.