PHP Build with Composer: Build Files, Scanners and CI
How Composer builds PHP applications, which files it needs, how to run static analysis, security scans and tests, and a complete GitHub Actions pipeline.
Posted
DevOps pipeline loop motif with the title PHP Build with Composer
PHP Build with Composer: Build Files, Scanners and CI
PHP is interpreted, so there is no compile step. The “build” is Composer installing locked dependencies and generating an optimised autoloader, followed by static analysis (PHPStan or Psalm), which does much of the checking a compiler does in other languages. Composer also runs project scripts and audits dependencies for known vulnerabilities.
In CI, each stage of the generic build pipeline maps to a Composer command, plugin or scanner. Press play, or step through it:
Source + composer.lock: A commit triggers CI. composer.json declares dependencies, composer.lock pins them, and composer validate --strict checks the two agree.
Install: composer install --no-interaction --prefer-dist installs exactly composer.lock from Packagist; CI caches Composer's download cache.
Lint and format: vendor/bin/php-cs-fixer fix --dry-run --diff fails on formatting changes; PHP_CodeSniffer and Laravel Pint are alternatives.
Static analysis: PHP has no compile step, so vendor/bin/phpstan analyse finds type errors and bugs before the tests run.
Test and coverage: vendor/bin/phpunit --coverage-text runs the tests, with coverage from PCOV or Xdebug.
Security scans in parallel: vendor/bin/psalm --taint-analysis traces untrusted input to dangerous sinks, composer audit checks dependencies, and Gitleaks scans for secrets.
Quality gate: Tests, coverage and every scanner are required checks, so a single failure stops the pipeline here.
Fail the build (fail): A failed check stops the pipeline at the gate, so nothing is packaged, signed or published.
Production build (pass): composer install --no-dev --optimize-autoloader --classmap-authoritative builds the production vendor/ tree; Box can package a PHAR.
SBOM and signing (pass): Syft generates the SBOM, and Sigstore cosign signs the release.
Ship (pass): The app and its vendor/ directory ship as a container image to a registry; libraries are published through Packagist instead.
composer update resolves new versions and rewrites composer.lock; only developers run it.
composer install installs exactly what the lockfile says; CI and production only run this.
--no-dev --optimize-autoloader (or --classmap-authoritative) removes dev tools and builds a fast classmap for production.
Platform requirements: config.platform.php in composer.json makes resolution use the production PHP version, even if a developer runs a newer one locally.