From 7fd215c782e11f2bc20517adeaa73ab3bac132ba Mon Sep 17 00:00:00 2001
From: Alies Lapatsin <5278175+alies-dev@users.noreply.github.com>
Date: Thu, 25 Jun 2026 11:05:54 +0200
Subject: [PATCH 1/3] feat: improve PHP-CS-Fixer config sharing and require PHP
8.4
- Add @PHP8x4Migration, @PHP8x4Migration:risky and @PHPUnit10x0Migration:risky
rulesets for automatic syntax/test modernization, plus numeric_literal_separator.
- Mark Config and Rules as @api to declare the supported BC surface.
- Add a smoke test covering Rules::get() and Config::create().
- Fix the stale raw-require path example in the rules file docblock.
- Bump required PHP to ^8.4 and drop 8.3 from the CI matrix.
- Restructure README: PHP-CS-Fixer first, then PHP_CodeSniffer, for clarity.
---
.github/workflows/test.yml | 1 -
.php-cs-fixer-rules.php | 11 +++-
IxDFCodingStandard/PhpCsFixer/Config.php | 1 +
IxDFCodingStandard/PhpCsFixer/Rules.php | 1 +
README.md | 75 ++++++++++++------------
composer.json | 2 +-
tests/PhpCsFixer/RulesTest.php | 27 +++++++++
7 files changed, 77 insertions(+), 41 deletions(-)
create mode 100644 tests/PhpCsFixer/RulesTest.php
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 1b65e17..d6e65e7 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -25,7 +25,6 @@ jobs:
- "lowest"
- "highest"
php-version:
- - "8.3"
- "8.4"
- "8.5"
operating-system:
diff --git a/.php-cs-fixer-rules.php b/.php-cs-fixer-rules.php
index 10e6ccb..d94a627 100644
--- a/.php-cs-fixer-rules.php
+++ b/.php-cs-fixer-rules.php
@@ -3,13 +3,19 @@
/**
* Shared PHP-CS-Fixer rules for PER projects.
* @see https://localheinz.com/articles/2023/03/10/sharing-configurations-for-php-cs-fixer-across-projects/
- * How to use:
- * $rules = require __DIR__.'/vendor/interaction-design-foundation/php-cs-fixer-rules.php';
+ *
+ * Prefer the autoloaded API: \IxDFCodingStandard\PhpCsFixer\Rules::get() (or Config::create()).
+ * This raw file is the no-autoloader fallback; require it directly when needed:
+ * $rules = require __DIR__.'/vendor/interaction-design-foundation/coding-standard/.php-cs-fixer-rules.php';
* $config->setRules($rules);
*/
return [
// Basic PER Coding Style 3.0 ruleset plus our overrides for it, see https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/ruleSets/PER-CS3x0.rst
'@PER-CS3x0' => true, // https://www.php-fig.org/per/coding-style/
+ // Auto-modernize syntax to the target PHP/PHPUnit version. Renovate bumps PHP-CS-Fixer, so new migration rules arrive for free.
+ '@PHP8x4Migration' => true,
+ '@PHP8x4Migration:risky' => true,
+ '@PHPUnit10x0Migration:risky' => true,
'new_with_parentheses' => ['anonymous_class' => true], // It will be changed in PHP-CS-Fixer v4.0 (but we want to enforce it), see https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/pull/8148
// overrides for PER-CS2.0/PER-CS3.0
'concat_space' => ['spacing' => 'none'], // make strings shorter "'hello' . $name . '!'" => "'hello'.$name.'!'"
@@ -71,6 +77,7 @@
'normalize_index_brace' => true,
'nullable_type_declaration' => ['syntax' => 'question_mark'],
'nullable_type_declaration_for_default_null_value' => true,
+ 'numeric_literal_separator' => ['strategy' => 'use_separator', 'override_existing' => false],
'object_operator_without_whitespace' => true,
'ordered_imports' => ['imports_order' => ['class', 'function', 'const']],
/*
diff --git a/IxDFCodingStandard/PhpCsFixer/Config.php b/IxDFCodingStandard/PhpCsFixer/Config.php
index 7af4490..02d7cc5 100644
--- a/IxDFCodingStandard/PhpCsFixer/Config.php
+++ b/IxDFCodingStandard/PhpCsFixer/Config.php
@@ -9,6 +9,7 @@
/**
* Pre-configured PHP-CS-Fixer config factory for IxDF projects.
* @see README.md for usage examples
+ * @api
*/
final class Config
{
diff --git a/IxDFCodingStandard/PhpCsFixer/Rules.php b/IxDFCodingStandard/PhpCsFixer/Rules.php
index f398324..c6658c4 100644
--- a/IxDFCodingStandard/PhpCsFixer/Rules.php
+++ b/IxDFCodingStandard/PhpCsFixer/Rules.php
@@ -5,6 +5,7 @@
/**
* Shared PHP-CS-Fixer rules for IxDF projects.
* @see https://mlocati.github.io/php-cs-fixer-configurator/
+ * @api
*/
final class Rules
{
diff --git a/README.md b/README.md
index 3f188c2..d16b589 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@
# IxDF Coding Standard
-An opinionated coding standard for PHP/Laravel projects. Provides two independent tools — use either one or both together:
+An opinionated coding standard for PHP/Laravel projects. It ships two independent tools that you can use separately or together:
-- **PHP_CodeSniffer** — custom sniffs for strict types and Laravel conventions
-- **PHP-CS-Fixer** — shared config with 80+ rules based on PER-CS 3.0
+- **PHP-CS-Fixer** — shared config based on the [latest PER Coding Style](https://www.php-fig.org/per/coding-style/) (currently PER-CS 3.0), plus formatting and modernization rules.
+- **PHP_CodeSniffer** — custom sniffs for strict types and Laravel conventions.
## Installation
@@ -16,21 +16,6 @@ An opinionated coding standard for PHP/Laravel projects. Provides two independen
composer require --dev interaction-design-foundation/coding-standard
```
-## PHP_CodeSniffer
-
-Create `phpcs.xml` in your project root:
-```xml
-
-
-
- app
- config
- database
- routes
- tests
-
-```
-
## PHP-CS-Fixer
Create `.php-cs-fixer.php` in your project root:
@@ -43,18 +28,17 @@ use IxDFCodingStandard\PhpCsFixer\Config;
return Config::create(__DIR__);
```
-With rule overrides:
+`Config::create()` ships a sensible default Finder and enables parallel runs, risky rules, and caching. Two optional arguments let you adjust it:
```php
+// Override individual rules.
return Config::create(__DIR__, ruleOverrides: [
'final_public_method_for_abstract_class' => false,
]);
```
-With a custom Finder:
-
```php
-use IxDFCodingStandard\PhpCsFixer\Config;
+// Provide your own Finder.
use PhpCsFixer\Finder;
$finder = Finder::create()->in(__DIR__)->name('*.php');
@@ -62,27 +46,48 @@ $finder = Finder::create()->in(__DIR__)->name('*.php');
return Config::create(__DIR__, finder: $finder);
```
-If you only need the rules array:
+Need only the rules array (e.g. to compose your own config)?
+
```php
$rules = \IxDFCodingStandard\PhpCsFixer\Rules::get();
```
-## Usage
+Run it:
```shell
-vendor/bin/phpcs # check with PHP_CodeSniffer
-vendor/bin/phpcbf # fix with PHP_CodeSniffer
-vendor/bin/php-cs-fixer fix --dry-run --diff # check with PHP-CS-Fixer
-vendor/bin/php-cs-fixer fix # fix with PHP-CS-Fixer
+vendor/bin/php-cs-fixer fix --dry-run --diff # check
+vendor/bin/php-cs-fixer fix # fix
```
-### Composer scripts (recommended)
+## PHP_CodeSniffer
-Add to your `composer.json`:
+Create `phpcs.xml` in your project root:
+
+```xml
+
+
+
+ app
+ config
+ database
+ routes
+ tests
+
+```
+
+Run it:
+
+```shell
+vendor/bin/phpcs # check
+vendor/bin/phpcbf # fix
+```
+
+## Composer scripts (recommended)
+
+Wire both tools into `composer.json` so the whole team runs them the same way:
```json
"scripts": {
- "cs": "@cs:fix",
"cs:check": ["@php-cs-fixer:dry", "@phpcs"],
"cs:fix": ["@php-cs-fixer", "@phpcbf"],
"phpcs": "phpcs -p -s --colors --report-full --report-summary",
@@ -92,11 +97,7 @@ Add to your `composer.json`:
}
```
-Then run:
-
```shell
-composer cs:check # run both tools in check mode
-composer cs:fix # run both tools in fix mode
-composer phpcs # PHP_CodeSniffer only
-composer php-cs-fixer # PHP-CS-Fixer only
+composer cs:check # check with both tools
+composer cs:fix # fix with both tools
```
diff --git a/composer.json b/composer.json
index 68bfff3..2406556 100644
--- a/composer.json
+++ b/composer.json
@@ -4,7 +4,7 @@
"license": "MIT",
"type": "phpcodesniffer-standard",
"require": {
- "php": "^8.3",
+ "php": "^8.4",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"friendsofphp/php-cs-fixer": "^3.89",
"slevomat/coding-standard": "^8.29",
diff --git a/tests/PhpCsFixer/RulesTest.php b/tests/PhpCsFixer/RulesTest.php
new file mode 100644
index 0000000..c00bdc4
--- /dev/null
+++ b/tests/PhpCsFixer/RulesTest.php
@@ -0,0 +1,27 @@
+getRules());
+ self::assertTrue($config->getRiskyAllowed());
+ }
+}
From 62c7bcdd89eff6b526251c5a2bb4092b765de81d Mon Sep 17 00:00:00 2001
From: Alies Lapatsin <5278175+alies-dev@users.noreply.github.com>
Date: Thu, 25 Jun 2026 11:25:46 +0200
Subject: [PATCH 2/3] refactor: drop phpcs sniffs already covered by
PHP-CS-Fixer
Now that the shared PHP-CS-Fixer config owns formatting, stop checking the
same issues with PHP_CodeSniffer (PHP-CS-Fixer is faster and auto-fixes).
Removed 30 sniffs whose concern is fully handled by an enabled fixer rule
(verified against the expanded 151-rule set), e.g. array syntax/indentation,
cast and operator spacing, trailing commas, yoda style, null coalesce,
short list, import ordering, scope indentation, superfluous whitespace.
Kept sniffs with no fixer equivalent in our config: single_quote,
native_function_casing, AND/OR operators, == vs ===, member var scope,
annotation-aware unused imports, and const/property spacing.
Generic.CodeAnalysis.EmptyStatement is kept: it detects empty control-structure
bodies, not stray semicolons (that is Slevomat UselessSemicolon, which is removed).
---
IxDFCodingStandard/ruleset.xml | 86 ++++------------------------------
1 file changed, 10 insertions(+), 76 deletions(-)
diff --git a/IxDFCodingStandard/ruleset.xml b/IxDFCodingStandard/ruleset.xml
index 9aa8c43..9ebdca8 100644
--- a/IxDFCodingStandard/ruleset.xml
+++ b/IxDFCodingStandard/ruleset.xml
@@ -13,13 +13,6 @@
-
-
-
- error
-
-
-
@@ -49,16 +42,20 @@
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
@@ -68,8 +65,6 @@
-
-
@@ -86,8 +81,6 @@
-
-
@@ -107,8 +100,6 @@
-
-
@@ -163,18 +154,12 @@
-
-
-
-
-
-
@@ -188,8 +173,6 @@
-
-
@@ -220,7 +203,6 @@
-
@@ -248,18 +230,13 @@
-
-
-
-
-
@@ -301,7 +278,6 @@
-
@@ -311,7 +287,6 @@
-
@@ -321,7 +296,6 @@
6
-
@@ -330,7 +304,6 @@
-
@@ -345,9 +318,6 @@
-
-
-
@@ -359,7 +329,6 @@
-
@@ -416,8 +385,6 @@
-
-
@@ -486,43 +453,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 5
-
From f7527b6e8ecafaaf897e916dc8e4f6a82ba50c93 Mon Sep 17 00:00:00 2001
From: Alies Lapatsin <5278175+alies-dev@users.noreply.github.com>
Date: Thu, 25 Jun 2026 11:40:37 +0200
Subject: [PATCH 3/3] refactor: drop PSR12 phpcs ref, keep only PSR1 structural
sniffs
PHP-CS-Fixer's @PER-CS3x0 (PER-CS supersedes PSR-12) already enforces every
PSR12 formatting concern, verified against the expanded fixer ruleset. Replace
the whole PSR12 ref with the three PSR1 sniffs PHP-CS-Fixer cannot cover:
side-effect separation, one-symbol-per-file, and method camelCase naming.
Const visibility stays enforced via SlevomatCodingStandard.Classes.ClassConstantVisibility.
README now states PHP-CS-Fixer is primary (owns formatting) and PHP_CodeSniffer
is supplementary, not a complete standard on its own.
---
IxDFCodingStandard/ruleset.xml | 49 +++++++---------------------------
README.md | 6 ++---
2 files changed, 13 insertions(+), 42 deletions(-)
diff --git a/IxDFCodingStandard/ruleset.xml b/IxDFCodingStandard/ruleset.xml
index 9ebdca8..9774b8f 100644
--- a/IxDFCodingStandard/ruleset.xml
+++ b/IxDFCodingStandard/ruleset.xml
@@ -13,47 +13,16 @@
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -365,6 +334,8 @@
+
+
diff --git a/README.md b/README.md
index d16b589..b4e4d0e 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@
# IxDF Coding Standard
-An opinionated coding standard for PHP/Laravel projects. It ships two independent tools that you can use separately or together:
+An opinionated coding standard for PHP/Laravel projects. The two tools play different roles and are meant to run together:
-- **PHP-CS-Fixer** — shared config based on the [latest PER Coding Style](https://www.php-fig.org/per/coding-style/) (currently PER-CS 3.0), plus formatting and modernization rules.
-- **PHP_CodeSniffer** — custom sniffs for strict types and Laravel conventions.
+- **PHP-CS-Fixer** (primary) — shared config based on the [latest PER Coding Style](https://www.php-fig.org/per/coding-style/) (currently PER-CS 3.0), plus formatting and modernization rules. It owns all code formatting and auto-fixes it.
+- **PHP_CodeSniffer** (supplementary) — adds the structural and semantic checks PHP-CS-Fixer cannot enforce (strict types, Laravel conventions, naming, complexity). Formatting rules already covered by PHP-CS-Fixer are intentionally **not** duplicated here, so PHP_CodeSniffer is not a complete standard on its own.
## Installation