A comprehensive quality assurance and continuous integration pipeline for PHP 8.3+ projects, written in Bash. Runs tools in a logical order designed to fail as quickly as possible, suitable for both local development and CI.
This package is written for and tested on Linux.
composer require --dev lts/php-qa-ci:dev-php8.4@devThe qa script will be installed in your project's bin directory. By default, Composer uses vendor/bin, but you can configure a custom location in your composer.json:
"config": {
"bin-dir": "bin"
}For Symfony projects, you can accept the prompts to run recipes, but you will then need to decide whether to stick with Symfony defaults or the php-qa-ci defaults (which are more extensive). If you decide to keep the php-qa-ci defaults, remove the config files created by the Symfony recipe:
# Revert to php-qa-ci PHPUnit configs (compare files first)
rm phpunit.xml.dist
ln -s vendor/lts/php-qa-ci/configDefaults/generic/phpunit.xmlYour project's composer.json must allow the required plugins:
{
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true,
"lts/php-qa-ci": true,
"phpstan/extension-installer": true
}
}
}PHP-QA-CI orchestrates multiple PHP quality tools across four phases:
Phase 1 -- Code Modification:
- Rector (safe functions, PHPUnit, PHP 8.4 upgrades)
- PHP CS Fixer
Phase 2 -- Linting and Validation: 3. PSR-4 Validation 4. Composer Checks 5. Strict Types Enforcement 6. PHP Lint 7. Composer Require Checker 8. Markdown Links Checker
Phase 3 -- Static Analysis: 9. PHPStan (level max)
Phase 4 -- Testing: 10. PHPUnit 11. Infection (mutation testing, optional, requires Xdebug)
Post-Success: PHPLoc (stats only, cannot fail)
See Pipeline Architecture for full details.
PHP-QA-CI uses a hybrid approach to tool delivery:
- PHARs (via PHIVE): PHPStan, PHP CS Fixer, Infection, Composer Require Checker -- delivered in
vendor-phar/ - Composer dependencies: PHPUnit, phpstan-strict-rules, phpstan-phpunit, parallel-lint
- Isolated Composer project: Rector -- in
tools/rector/with its owncomposer.jsonto prevent dependency conflicts
The phpstan/phpstan package is in the replace section of composer.json since PHPStan is provided via PHAR. This prevents version conflicts when consuming projects also require PHPStan extensions.
PHP-QA-CI ships with custom PHPStan rules that are auto-loaded via the PHPStan extension installer:
- ForbidMockingFinalClassRule -- Prevents mocking of final classes
- ForbidAllowMockWithoutExpectationsRule -- Bans
#[AllowMockObjectsWithoutExpectations] - ForbidDangerousFunctionsRule -- Bans exec/eval/unserialize and similar
- ForbidEmptyCatchBlockRule -- Requires catch blocks to have a body
- RequireDeclareStrictTypesRule -- Requires
declare(strict_types=1)in all PHP files
Projects can add their own rules alongside these defaults.
Automatically install the GitHub Actions workflow for continuous integration:
vendor/lts/php-qa-ci/scripts/install-github-actions.bashThis will:
- Create
.github/workflows/qa.ymlwith an optimized QA pipeline - Auto-detect your PHP version from
composer.json - Configure smart caching for faster builds
- Set up artifact storage for test results
Configure GitHub branch protection rules with sensible defaults:
# Standard protection (admins can bypass)
vendor/lts/php-qa-ci/scripts/setup-branch-protection.bash
# Hardened protection (CI enforced for everyone)
vendor/lts/php-qa-ci/scripts/setup-branch-protection.bash --hardenPrerequisites: Requires GitHub CLI (gh) installed and authenticated.
PHP-QA-CI includes three GitHub Actions workflows in .github/workflows/:
ci.yml-- Runs on push/PR tophp8.4, executesbash ci.bashqa.yml-- Template workflow for consuming projects (copy to your project)update-deps.yml-- Weekly scheduled workflow that updates all dependencies (Composer, PHARs via PHIVE, isolated Rector), runs the full QA pipeline, and creates an auto-merge PR if green
See GitHub Actions Integration for setup details.
PHP-QA-CI integrates with Claude Code to provide development guardrails and automation.
Deploy skills and hooks to your project:
vendor/lts/php-qa-ci/scripts/deploy-skills.bash vendor/lts/php-qa-ci .This will:
- Copy hooks to
.claude/hooks/ - Register them in
.claude/settings.json - Detect and configure hooks-daemon if present (see hooks-daemon documentation for installation)
- Migrate from legacy classic hooks if found
php-qa-ci__auto-continue.py-- Reduces confirmation promptsphp-qa-ci__prevent-destructive-git.py-- Blocks commands that destroy uncommitted changesphp-qa-ci__discourage-git-stash.py-- Discourages git stash with escape hatchphp-qa-ci__block-plan-time-estimates.py-- Prevents time estimates in plan documentsphp-qa-ci__validate-claude-readme-content.py-- Ensures docs contain instructions, not logsphp-qa-ci__enforce-markdown-organization.py-- Enforces doc organization
See .claude/hooks/README.md for detailed hook documentation after deployment.
PHP-QA-CI registers three Composer plugins:
- PhiveUpdatePlugin -- Manages PHAR installation via PHIVE
- SkillsDeployPlugin -- Deploys Claude Code skills and hooks
- PhpStanGuardPlugin -- Prevents
phpstan/phpstanfrom being installed alongside the PHAR
Comprehensive documentation is available in the ./docs folder:
- Pipeline Architecture -- Tool execution order and phases
- Tools Overview -- All tools with configuration details
- Configuration -- Customizing tool settings and overrides
- Coding Standards -- PHP CS Fixer and Rector configuration
- GitHub Actions Integration -- CI/CD setup guide
- Continuous Integration -- General CI usage and workflows
- Platform Detection -- Symfony/Laravel specific settings
Tool-specific documentation:
- PHPStan -- Static analysis configuration and custom rules
- PHPUnit -- Test runner configuration and modes
- Infection -- Mutation testing setup
If you are running multiple PHP versions, you can specify which one to use:
export PHP_QA_CI_PHP_EXECUTABLE=/bin/php84
vendor/bin/qa
# Or inline:
PHP_QA_CI_PHP_EXECUTABLE=/bin/php84 vendor/bin/qa# Run only PHPStan
vendor/bin/qa -t stan
# Run only PHP CS Fixer
vendor/bin/qa -t fixer
# Run on specific path
vendor/bin/qa -t stan -p src/Domainphp8.4-- Default branch, targets PHP 8.4php8.3-- PHP 8.3 support
This package was brought to you by Long Term Support LTD, a company run and founded by Joseph Edmonds.
You can get in touch with Joseph at https://ltscommerce.dev/
Check out Joseph's recent book The Art of Modern PHP 8