Open-source project
PHPCompatibility/PHPCompatibility avatar
PHPCompatibility/PHPCompatibility

PHPCompatibility: static PHP version checks inside PHP_CodeSniffer

PHP Compatibility check for PHP_CodeSniffer

2,308 stars202 forksPHPLGPL-3.0

At a glance

What is it?
PHPCompatibility is a ruleset of sniffs for PHP_CodeSniffer that reads source and flags PHP features belonging to other versions. It earns its place in a library that must stay installable on PHP 7.2 when CI cannot retest every version by hand.
Who is it for?
Adopt PHPCompatibility when a library or plugin has to keep working on PHP versions nobody runs locally, because the sniffs read source statically and cost one phpcs invocation. Leave it out when the code has to be validated on PHP 8.5 behaviour rather than on API availability, since no sniff executes anything and the old end of the range, anything before PHP 5.1, is patchy.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Sniffs bolted onto PHP_CodeSniffer for cross-version checks

PHPCompatibility ships no binary and no runtime of its own. It is a set of sniffs for PHP_CodeSniffer, and the job of each sniff is to spot a PHP construct, a function or an ini setting that exists in one version of the language and not in another, so source can be read against a target range without ever being executed. That places it in the same category as a linter: the standard joins a phpcs run you already have instead of asking for a second toolchain in CI.

The input is source text plus the versions you care about. The output is a list of lines that would break on the version you are not running. Libraries, plugins and packages with a wide install base get the most from that arrangement, because their code ends up on machines and interpreters that nobody on the team controls.

The version floor sits at PHP 7.2 and PHPCS 4.0.2

Three floors are stated up front: PHP 7.2+, PHP_CodeSniffer 4.0.2+ and PHPCSUtils 1.1.2+. The build badge names the matrix the project tests itself against, which runs from PHP 7.2 through 8.5 plus nightly, so the sniffs are exercised on far more PHP versions than most consumers will ever install.

A few lines below, the same section keeps a short history of what was dropped. Version 8.0.0 of the standard also works with PHP_CodeSniffer 3.x, version 9.0.0 gave up PHP_CodeSniffer 1.5.x and 2.x versions below 2.3.0, and version 10.0.0 raised the floor to PHP 7.2 and PHP_CodeSniffer 4.0.2. That history leaves a hole for one group of readers: a team still on PHP_CodeSniffer 3.x is sent back to the 8.0.0 line, while the install commands elsewhere on the same page only produce the 10.0.0 line, which the requirements say needs 4.0.2 or newer.

Composer became the only supported install path

From version 10.0.0 onwards, Composer is the documented and only supported way to install this standard. From the root of a project, two commands do the job: the first allows the Composer PHPCS plugin to run, the second pulls the standard in as a dev dependency. Composer then installs the dependencies and registers the PHPCompatibility ruleset with PHP_CodeSniffer through that plugin, which is why there is no manual path setting to configure.

bash
composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer require --dev phpcompatibility/php-compatibility:"^10.0.0@dev"

A global install mirrors both commands with the global prefix, which puts the standard on the account that runs phpcs for every project on the machine:

bash
composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
composer global require --dev phpcompatibility/php-compatibility:"^10.0.0@dev"

Upgrading follows the same prefix pattern, with update in place of require and `--with-dependencies` to bring PHPCSUtils and the sniffer along:

bash
# Project local install
composer update phpcompatibility/php-compatibility --with-dependencies

# Global install
composer global update phpcompatibility/php-compatibility --with-dependencies

Verifying registration and scanning a tree from the shell

Registration can be checked before any code is scanned. Running `vendor/bin/phpcs -i` prints the standards PHP_CodeSniffer can see, and both PHPCompatibility and PHPCSUtils should appear in that list. A missing line there means the Composer PHPCS plugin never ran, so the allow-plugins entry from the install step is the first thing to re-check.

Scanning then comes down to one invocation per project tree:

bash
# Project local install
vendor/bin/phpcs -ps . --standard=PHPCompatibility

# Global install
%USER_DIRECTORY%/Composer/vendor/bin/phpcs -ps . 

Two things in that block deserve a second look. The global variant carries no `--standard=PHPCompatibility` flag at all, so in that form the standard has to arrive from the project's own ruleset file or from whatever PHP_CodeSniffer treats as its default. The same line also spells the vendor directory with a Windows style user placeholder instead of a real path, so pasting it verbatim on Linux or macOS will not find the binary.

Coverage stays under 100 percent and thins out before PHP 5.1

The project states its own target plainly: cover every compatibility change introduced since PHP 5.0, and in the same breath admit that coverage is not yet 100% and that the work is ongoing, with progress tracked on the GitHub issue tracker rather than published as a table. No sniff count appears anywhere, so auditing coverage means reading the issue tracker or walking the sniff tree yourself.

The weak spot is the old end of that range. Pull requests that check PHP 4 code, especially PHP 4 against PHP 5.0, are wanted because legacy systems still need help, yet coverage for changes introduced before PHP 5.1 will remain patchy, and the stated reason is that sniffs for those changes are not being developed. A team carrying twenty year old code therefore gets less from this standard than a team supporting PHP 7.2 and up, and that gap is a deliberate one.

A sniff tree and a ruleset, with its own test harness

The repository layout matches how the standard gets used. The `PHPCompatibility/` directory holds the sniff tree, `PHPCSAliases.php` sits at the top level to register sniff names with PHP_CodeSniffer, `composer.json` carries the dependencies and the plugin allow list that make the Composer install work, and `phpcs.xml.dist` is the ruleset the project uses to check its own code.

The rest of the top level shows how the sniffs are kept honest. Two PHPUnit configuration files sit side by side, `phpunit.xml.dist` and `phpunit10.xml.dist`, together with `phpunit-bootstrap.php`, so the sniff suite is executed under an older and a newer PHPUnit layout instead of one. A `.coveralls.yml` entry and the coverage badge point at line coverage for those tests, while the `.github/` directory holds the two workflows the badges name, `basics.yml` for the coding standard build and `test.yml` for the PHP test matrix. The package is offered under LGPL-3.0, and although its README links a licence badge and lists a License section in the table of contents, no redistribution or bundling guidance appears in the README text itself.

The install command targets an alpha line of the standard

Set the install commands next to the sequence of numbered builds and a gap opens. Both composer commands ask for `^10.0.0@dev`, the Packagist badge points at the dev-develop branch, and the repository default branch is develop, so the newest finished tag is 9.3.5 from 2019-12-27 while the two 10.x tags are 10.0.0-alpha1 from 2025-10-21 and 10.0.0-alpha2 from 2025-11-28, and the last push was on 2026-09-25.

Following the page verbatim therefore hands you the unreleased line of the standard rather than the last finished one, and the `@dev` suffix in that constraint is what lets Composer resolve it at all. For a team that tracks the project closely that is a reasonable bet; for a team that wants a frozen version in a lock file it is not. Anyone arriving from an older version is pointed at a separate upgrade guide before touching the composer commands, and no summary of what the move to 10.0.0 changes is offered.

Static scanning versus running your own version matrix

The honest alternative is to stop reading source and start running the code: put the target PHP versions into a test matrix and let the test suite answer. That is how this project protects itself, with a test badge naming PHP 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5 and nightly. Executing code catches what static reading cannot, including a function whose signature survived while its behaviour changed, at the price of one job per version for every project you maintain.

PHPCompatibility takes the opposite trade. It never runs the code, so it fits in seconds inside a local run or a pre commit hook, but it can only report what its sniffs were written to recognise and it cannot see which polyfill or framework shim your project already ships. Its table of contents reserves dedicated sections for both gaps, one on framework, CMS and polyfill specific rulesets and one called `testVersion` in the ruleset versus command-line, yet the README text stops before either of them, so the option names behind `testVersion` are not spelled out there.

Editorial conclusion

Adopt PHPCompatibility when a library or plugin has to keep working on PHP versions nobody runs locally, because the sniffs read source statically and cost one phpcs invocation. Leave it out when the code has to be validated on PHP 8.5 behaviour rather than on API availability, since no sniff executes anything and the old end of the range, anything before PHP 5.1, is patchy. Before committing, run vendor/bin/phpcs -i, confirm the PHP_CodeSniffer version in the project meets the 4.0.2 floor, and decide deliberately whether to pin the 9.3.5 build or follow the alpha 10.0.0 branch.

Frequently asked questions

Does PHPCompatibility need PHP_CodeSniffer to run?

Yes. It is a set of sniffs for PHP_CodeSniffer, and the stated requirements are PHP 7.2+, PHP_CodeSniffer 4.0.2+ and PHPCSUtils 1.1.2+. Composer installs the dependencies and registers the ruleset with PHP_CodeSniffer through the Composer PHPCS plugin.

Can I install PHPCompatibility without Composer?

Not for version 10.0.0, where Composer is the only supported type of installation. The README gives both a project level install and a global one, and each starts by allowing the dealerdirect/phpcodesniffer-composer-installer plugin.

How do I check that the PHPCompatibility ruleset was registered?

Run vendor/bin/phpcs -i on the command line. PHPCompatibility and PHPCSUtils should both be listed among the available standards, and if one is missing the Composer PHPCS plugin did not register anything.

Does PHPCompatibility check PHP versions older than 5.0?

Partly. The project aims to cover changes introduced since PHP 5.0 and welcomes pull requests covering PHP 4 code, but coverage for changes introduced before PHP 5.1 will remain patchy because sniffs for those changes are not being developed.

Will PHPCompatibility catch problems that only show up when the code runs?

Not on its own. It reads source for use of PHP features from other versions and never executes anything, so it cannot observe behaviour changes inside a function that kept its signature. The project's own tests run against PHP 7.2 through 8.5 and nightly.

Official sources

  1. License: LGPL-3.0
  2. PHPCompatibility/PHPCompatibility on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/phpcompatibility-phpcompatibility.svg)](https://hysenlabs.com/projects/phpcompatibility-phpcompatibility)

Was this useful?