aryeohq / phpstan-rules
Aryeo's Custom PHPStan Rules
Installs: 245
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Type:phpstan-extension
Requires
- php: ^8.2
- phpstan/phpstan: ^2.0.4
Requires (Dev)
README
How to Install & Use in Your Project
Follow these steps to integrate this custom‐rule pack into any PHP project running PHPStan:
-
Require via Composer (adjust package name as needed):
composer require --dev aryeo/phpstan-rules
-
Add (or merge)
rules.neon
into your application’s PHPStan config:-
In your project root, you probably have a
phpstan.neon
orphpstan.neon.dist
. -
Ensure it includes this package’s
rules.neon
. For example:# phpstan.neon.dist includes: - vendor/aryeo/phpstan-rules/rules.neon parameters: # 1) Enable/disable test rules: aryeo: tests: enabled: true # Override TestCase class if needed testCaseClass: App\Tests\TestCase # 2) Your other PHPStan settings: level: max paths: - src - tests
-
The
includes:
line loads all sections from the package’srules.neon
(includingconditionalTags
,parameters
,parametersSchema
, andservices
).
-
-
Override parameters (optional):
-
If your project’s tests extend from
App\Tests\TestCase
, set:parameters: aryeo: tests: testCaseClass: App\Tests\TestCase
-
If you want to disable all PHPStan test rules, set:
parameters: aryeo: tests: enabled: false
-
Leaving
aryeo.tests.enabled
out entirely will default totrue
(because the package’srules.neon
hasenabled: true
by default), so you only need to override it when you want it off.
-
-
Run PHPStan as usual:
vendor/bin/phpstan analyse -c phpstan.neon.dist
-
If you kept the default
testCaseClass: Tests\TestCase
but your project uses a different namespace, you will see errors like:ClassAryeo\PHPStan\Rules\Tests\ClassMustExtendTestCaseRule: Class App\Tests\SomeTest does not extend Tests\TestCase
In that case, update
aryeo.tests.testCaseClass
accordingly.
-
Rule Descriptions & Examples
Below is a quick summary of what each rule does, plus usage examples.
Aryeo\PHPStan\Rules\Enums\EnumCasePascalCaseRule
-
Always active (no conditional toggle).
-
Enforces: Every Enum
case
name must be PascalCase. -
Why? PHPStan’s default
EnumCase
rule focuses on visibility or value uniqueness, but this custom rule ensures stylistic consistency across your codebase. -
Example Violation:
enum Status: string { case pending; // invalid: “pending” is not PascalCase case OrderPickedUp; // invalid: starts with uppercase but next word not separated by capital case Shipped; // valid if that’s exactly PascalCase (single‐word “Shipped”) }
-
Fix:
enum Status: string { - case pending; - case OrderPickedUp; + case Pending; + case OrderPickedUp; // if you intended “OrderPickedUp” as PascalCase, ensure proper casing case Shipped; }
Aryeo\PHPStan\Rules\Tests\ClassMustExtendTestCaseRule
-
Conditional: Only runs when
aryeo.tests.enabled
=true
. -
Constructor Argument:
$testCaseClass
(e.g.,'Tests\TestCase'
or'App\Tests\TestCase'
). -
Enforces: Every class under your
tests/
directory (or any file matching*Test.php
) must extend the given base test case class. -
Why? Some teams create a
BaseTestCase
orTestCase
with common setup/teardown. This rule ensures no test accidentally extends\PHPUnit\Framework\TestCase
directly or some other class. -
Example Violation:
// Assume: aryeo.tests.testCaseClass = 'App\Tests\TestCase' namespace App\Tests\Feature; use PHPUnit\Framework\TestCase; class UserTest extends TestCase { public function testSomething() { $this->assertTrue(true); } }
- Error:
Class UserTest does not extend App\Tests\TestCase.
- Error:
-
Fix:
use PHPUnit\Framework\TestCase; class UserTest extends TestCase
to:
use App\Tests\TestCase; // your own base test case class UserTest extends TestCase
Aryeo\PHPStan\Rules\Tests\MethodNamePrefixRule
-
Conditional: Only runs when
aryeo.tests.enabled
=true
. -
Constructor Argument:
$testCaseClass
. -
Enforces: In any class extending
$testCaseClass
, all public test methods must start with a given prefix (e.g.,test
). -
Why? PHPUnit’s default behavior is to look for methods that start with
test
, but you may have configured fallback annotations, or you want to enforce a uniform method naming convention. This rule ensures that any test method is namedtestSomething…
rather thansomethingTest()
orit_does_something()
. -
Example Violation:
class UserTest extends App\Tests\TestCase { public function doesSomething() // invalid: missing “test” prefix { $this->assertTrue(true); } public function testItWorks() // valid { $this->assertTrue(true); } }
-
Fix: Rename method to:
public function testDoesSomething() { $this->assertTrue(true); }
Aryeo\PHPStan\Rules\Tests\MethodNameSnakeCaseRule
-
Conditional: Only runs when
aryeo.tests.enabled
=true
. -
Constructor Argument:
$testCaseClass
. -
Enforces: Test method names in classes extending
$testCaseClass
must usesnake_case
rather thancamelCase
orPascalCase
. -
Why? Some teams prefer writing test names in snake_case so that method names—when read—describe behavior in a consistent way (e.g.,
test_user_can_register
). If your team enforces snake_case, this rule flags camelCase or PascalCase. -
Example Violation:
class UserTest extends App\Tests\TestCase { public function testUserCanRegister() // invalid: camelCase/PascalCase { $this->assertTrue(true); } public function test_user_can_login() // valid: snake_case { $this->assertTrue(true); } }
-
Fix: Convert to snake_case:
- public function testUserCanRegister() + public function test_user_can_register() { $this->assertTrue(true); }