| name | composer-tooling |
| description | Composer conventions for any PHP project: dependency management, version constraints, PSR-4 autoloading, scripts, platform requirements, and the composer.json vs composer.lock contract. Stack-agnostic — referenced by every PHP plugin in the marketplace.
Use this skill to:
- Read composer.json to detect the PHP version, framework, and key packages before writing code.
- Add dependencies with correct version constraints and the right require vs require-dev placement.
- Configure PSR-4 autoloading and regenerate the autoloader after adding namespaces.
- Use composer scripts and platform config consistently.
Do NOT use this skill for:
- PHP language idioms — see php-foundation:php-conventions.
- Testing setup and runners — see php-foundation:php-testing.
- Framework-specific package guidance (Laravel/Symfony bundles) — those live in framework plugin skills.
|
Composer Tooling (stack-agnostic)
Composer is the dependency manager and autoloader entry point for every modern PHP project. Read composer.json before doing anything else — it tells you the PHP version, the framework, and the available packages.
Project detection
cat composer.json
test -f composer.lock && echo "locked"
Key fields to read:
require.php — minimum PHP version (drives which language features you may use).
require — runtime dependencies; the framework marker lives here (laravel/framework, symfony/framework-bundle).
require-dev — dev/test tooling (phpunit, pest, phpstan, pint, php-cs-fixer).
autoload.psr-4 — namespace → directory map.
config.platform.php — pins the version the resolver targets (may differ from the runtime PHP).
composer.json vs composer.lock
composer.json declares intent — version ranges you accept.
composer.lock records the exact resolved versions. It is committed and is the source of truth for composer install.
| Command | Effect |
|---|
composer install | Installs the exact versions from composer.lock. Use in CI/deploy. |
composer update <pkg> | Re-resolves the named package, rewrites the lock. Use deliberately. |
composer require <pkg> | Adds to composer.json + updates the lock for that package. |
composer require --dev <pkg> | Same, into require-dev. |
Never hand-edit composer.lock. Never run a bare composer update (updates everything) as part of a focused feature change.
Version constraints
{
"require": {
"php": "^8.2",
"guzzlehttp/guzzle": "^7.8"
}
}
- Caret
^7.8 — allows >=7.8.0 <8.0.0. The default; respects SemVer.
- Tilde
~7.8.0 — allows >=7.8.0 <7.9.0. Tighter; use when you must pin to a minor.
- Exact
7.8.3 — avoid except to work around a specific broken release.
- Avoid
* and unbounded >= — they break reproducibility.
Adding a dependency — checklist
- Confirm it is not already provided transitively (
composer why-not <pkg> / check existing require).
- Choose
require (runtime) vs require-dev (tools/tests) correctly.
- Use a caret constraint unless the project convention says otherwise.
- Run
composer require <pkg> so the lockfile updates atomically.
- Verify nothing else moved: review the
composer.lock diff — only the new package and its deps should change.
PSR-4 autoloading
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
}
}
- Namespace prefix maps to a base directory; sub-namespaces map to sub-directories, class name = file name.
- After adding a new top-level namespace mapping, run
composer dump-autoload.
- Keep test namespaces in
autoload-dev so they are excluded from production autoload maps.
- For deploy/CI, generate an optimized classmap:
composer dump-autoload --optimize (or --classmap-authoritative).
Scripts
{
"scripts": {
"test": "phpunit",
"stan": "phpstan analyse",
"cs": "php-cs-fixer fix"
}
}
Run via composer test, composer stan. Prefer existing scripts over invoking the binary directly — they encode the project's intended flags. Discover them with composer run-script --list.
Platform requirements
{
"config": {
"platform": {
"php": "8.2.0"
}
}
}
config.platform.php tells Composer which PHP version to resolve against, independent of the local CLI version — keep it aligned with the production runtime so the lockfile is deployable.