Run PHPCS once per project ruleset, optionally in parallel.
This is useful for monorepos where each package has its own phpcs.xml.dist. Instead of merging those rulesets into one PHPCS run, phpcs-parallel runs an isolated PHPCS process for each matched config.
composer require --dev wpelevator/phpcs-parallelRun PHPCS for every matched config:
vendor/bin/phpcs-parallel --config-pattern='packages/*' --processes=4Pass PHPCS options after --:
vendor/bin/phpcs-parallel --config-pattern='packages/*' --processes=4 -- -s --report=summaryRun PHPCBF the same way:
vendor/bin/phpcbf-parallel --config-pattern='packages/*' --processes=4You can repeat --config-pattern or provide comma-separated patterns. Patterns are shell-style globs matched with PHP fnmatch(), not regular expressions. They may match either project directories or config files:
vendor/bin/phpcs-parallel --config-pattern='packages/*' --config-pattern='apps/*/phpcs.xml.dist'
vendor/bin/phpcs-parallel --config-pattern='packages/*,apps/*/phpcs.xml.dist'Each matched config runs as:
phpcs --standard=/path/to/package/phpcs.xml.dist /path/to/packageWhen project directories are provided explicitly, each directory uses the first config found in that directory, falling back to the nearest parent config. Config names are checked in this order:
.phpcs.xmlphpcs.xml.phpcs.xml.distphpcs.xml.dist
When no project directories are provided, the current working directory is recursively searched for matching config files. --config-pattern can match either project directory paths or config file paths. Patterns use shell-style glob syntax, for example packages/* or apps/*/phpcs.xml.dist; regex syntax such as packages/(foo|bar) or packages/.+ is not supported. Passing both project directories and --config-pattern combines explicit projects with discovered projects and deduplicates them by project root.
{
"scripts": {
"lint": "phpcs-parallel --config-pattern='packages/*' --processes=4 -- -s",
"format": "phpcbf-parallel --config-pattern='packages/*' --processes=4"
}
}The example directory contains a small monorepo with two packages, each using a different ruleset (PSR12 and WordPress), wired up via composer.json lint/format scripts:
cd example
composer install
composer lint
composer formatRun the same checks used by CI:
composer lint
composer analyse
composer testRun a specific test suite:
vendor/bin/phpunit --testsuite Unit
vendor/bin/phpunit --testsuite IntegrationGenerate PHPUnit coverage reports (requires Xdebug or PCOV):
composer test:coverageCoverage output is written to the terminal, tests/coverage/clover.xml, and tests/coverage/html.
- Dependency directories are skipped during discovery:
.git,vendor,node_modules,bower_components. - The wrapper returns the highest child exit code for PHPCS/PHPCBF lint/fix results. Runtime/tool errors are promoted to at least exit code
3. - Child process output is streamed through Symfony Console and prefixed with the project label.
- Use explicit project directories instead of patterns if needed:
vendor/bin/phpcs-parallel packages/foo packages/bar.
This project is open-sourced under the MIT License. See LICENSE for details.