symplify / phpstan-rules
Set of Symplify rules for PHPStan
Fund package maintenance!
tomasvotruba
www.paypal.me/rectorphp
Installs: 5 095 998
Dependents: 159
Suggesters: 2
Security: 0
Stars: 166
Watchers: 5
Forks: 25
Open Issues: 0
Type:phpstan-extension
Requires
- php: ^7.4|^8.0
- nette/utils: ^3.2|^4.0
- phpstan/phpstan: ^2.0
- webmozart/assert: ^1.11
- dev-main
- 14.1.0
- 14.0.4
- 14.0.3
- 14.0.2
- 14.0.1
- 14.0.0
- 13.0.1
- 13.0.0
- 12.7.0
- 12.6.4
- 12.6.3
- 12.6.2
- 12.6.1
- 12.6.0
- 12.5.2
- 12.5.1
- 12.5.0
- 12.4.9
- 12.4.8
- 12.4.7
- 12.4.6
- 12.4.5
- 12.4.4
- 12.4.3
- 12.4.2
- 12.4.1
- 12.4.0
- 12.3.1
- 12.3.0.72
- 12.3.0
- 12.2.7.72
- 12.2.7
- 12.2.6.72
- 12.2.6
- 12.2.5.72
- 12.2.5
- 12.2.4.72
- 12.2.4
- 12.2.3.72
- 12.2.3
- 12.2.2.72
- 12.2.2
- 12.2.1.72
- 12.2.1
- 12.2.0.72
- 12.2.0
- 12.1.4.72
- 12.1.4
- 12.1.3.72
- 12.1.3
- 12.1.2.72
- 12.1.2
- 12.1.1.72
- 12.1.1
- 12.1.0.72
- 12.1.0
- 12.0.4.72
- 12.0.4
- 12.0.3.72
- 12.0.3
- 12.0.2.72
- 12.0.2
- 12.0.1.72
- 12.0.1
- 12.0.0.72
- 12.0.0
- 11.4.1.72
- 11.4.1
- 11.4.0.72
- 11.4.0
- 11.3.5.72
- 11.3.5
- 11.3.4.72
- 11.3.4
- 11.3.3.72
- 11.3.3
- 11.3.2.72
- 11.3.2
- 11.3.1.72
- 11.3.1
- 11.3.0.72
- 11.3.0
- 11.2.5.72
- 11.2.5
- 11.2.4.72
- 11.2.4
- 11.2.3.72
- 11.2.3
- 11.2.2.72
- 11.2.2
- 11.2.1
- 11.2.0.72
- 11.2.0
- 11.1.28.72
- 11.1.28
- 11.1.27.72
- 11.1.27
- 11.1.26.72
- 11.1.26
- 11.1.25.72
- 11.1.25
- 11.1.24
- 11.1.23
- 11.1.22
- 11.1.21
- 11.1.20
- 11.1.19
- 11.1.18
- 11.1.17
- 11.1.16
- 11.1.15
- 11.1.14
- 11.1.13
- 11.1.12
- 11.1.11
- 11.1.10
- 11.1.9
- 11.1.8
- 11.1.7
- 11.1.6
- 11.1.5
- 11.1.4
- 11.1.1
- 11.1.0
- 11.0.9
- 11.0.8
- 11.0.7
- 11.0.6
- 11.0.5
- 11.0.4
- 11.0.3
- 11.0.2
- 11.0.1
- 11.0.0
- 10.3.3
- 10.3.2
- 10.3.1
- 10.3.0
- 10.2.11
- 10.2.10
- 10.2.9
- 10.2.8
- 10.2.7
- 10.2.6
- 10.2.5
- 10.2.4
- 10.2.3
- 10.2.2
- 10.2.1
- 10.2.0
- 10.1.4
- 10.1.3
- 10.1.2
- 10.1.1
- 10.1.0
- 10.0.25
- 10.0.24
- 10.0.23
- 10.0.22
- 10.0.21
- 10.0.20
- 10.0.19
- 10.0.18
- 10.0.17
- 10.0.16
- 10.0.15
- 10.0.14
- 10.0.13
- 10.0.12
- 10.0.11
- 10.0.10
- 10.0.9
- 10.0.8
- 10.0.7
- 10.0.6
- 10.0.5
- 10.0.4
- 10.0.3
- 10.0.2
- 10.0.1
- 10.0.0
- 10.0.0-beta17
- 10.0.0-beta16
- 10.0.0-beta15
- 10.0.0-beta14
- 10.0.0-beta13
- 10.0.0-beta12
- 10.0.0-beta11
- 10.0.0-beta10
- 10.0.0-beta9
- 10.0.0-beta8
- 10.0.0-beta7
- 10.0.0-beta6
- 10.0.0-beta5
- 10.0.0-beta4
- 10.0.0-beta3
- 10.0.0-beta2
- 10.0.0-beta1
- 9.4.70
- 9.4.69
- 9.4.68
- 9.4.67
- 9.4.66
- 9.4.65
- 9.4.64
- 9.4.63
- 9.4.62
- 9.4.61
- 9.4.60
- 9.4.59
- 9.4.58
- 9.4.57
- 9.4.56
- 9.4.55
- 9.4.54
- 9.4.53
- 9.4.52
- 9.4.51
- 9.4.50
- 9.4.49
- 9.4.48
- 9.4.47
- 9.4.46
- 9.4.45
- 9.4.44
- 9.4.43
- 9.4.42
- 9.4.41
- 9.4.40
- 9.4.39
- 9.4.38
- 9.4.37
- 9.4.36
- 9.4.35
- 9.4.34
- 9.4.33
- 9.4.32
- 9.4.31
- 9.4.30
- 9.4.29
- 9.4.28
- 9.4.27
- 9.4.26
- 9.4.25
- 9.4.24
- 9.4.23
- 9.4.22
- 9.4.21
- 9.4.20
- 9.4.19
- 9.4.18
- 9.4.17
- 9.4.16
- 9.4.15
- 9.4.14
- 9.4.13
- 9.4.12
- 9.4.11
- 9.4.10
- 9.4.9
- 9.4.8
- 9.4.7
- 9.4.6
- 9.4.5
- 9.4.4
- 9.4.3
- 9.4.2
- v9.4.1
- v9.4.0
- v9.3.27
- v9.3.26
- v9.3.25
- v9.3.24
- v9.3.23
- v9.3.22
- v9.3.21
- v9.3.20
- v9.3.19
- v9.3.18
- v9.3.17
- v9.3.16
- v9.3.15
- v9.3.14
- v9.3.13
- v9.3.12
- v9.3.11
- v9.3.10
- v9.3.8
- v9.3.6
- v9.3.5
- v9.3.4
- v9.3.3
- v9.3.1
- v9.3.0
- v9.2.24
- v9.2.23
- v9.2.22
- v9.2.21
- v9.2.20
- v9.2.19
- v9.2.18
- v9.2.17
- v9.2.16
- v9.2.15
- v9.2.14
- v9.2.13
- v9.2.12
- v9.2.11
- v9.2.10
- v9.2.9
- v9.2.8
- v9.2.7
- v9.2.6
- v9.2.5
- v9.2.4
- v9.2.3
- v9.2.2
- 9.2.1
- 9.2.0
- 9.1.9
- 9.1.8
- 9.1.7
- 9.1.6
- 9.1.5
- 9.1.4
- 9.1.3
- 9.1.1
- 9.1.0
- 9.0.50
- 9.0.49
- 9.0.48
- 9.0.47
- 9.0.46
- 9.0.45
- 9.0.44
- 9.0.43
- 9.0.42
- 9.0.41
- 9.0.40
- 9.0.39
- 9.0.38
- 9.0.37
- 9.0.36
- 9.0.35
- 9.0.34
- 9.0.33
- 9.0.32
- 9.0.31
- 9.0.30
- 9.0.29
- 9.0.28
- 9.0.27
- 9.0.26
- 9.0.25
- 9.0.24
- 9.0.23
- 9.0.22
- 9.0.21
- 9.0.20
- 9.0.19
- 9.0.18
- 9.0.17
- 9.0.16
- 9.0.15
- 9.0.14
- 9.0.13
- 9.0.12
- 9.0.11
- 9.0.10
- 9.0.9
- 9.0.8
- 9.0.7
- 9.0.6
- 9.0.5
- 9.0.4
- 9.0.3
- 9.0.2
- 9.0.1
- 9.0.0
- 9.0.0-rc1
- 9.0.0-BETA9
- 9.0.0-BETA8
- 9.0.0-BETA7
- 9.0.0-BETA6
- 9.0.0-BETA5
- 9.0.0-BETA4
- 9.0.0-BETA3
- 9.0.0-BETA2
- 9.0.0-BETA1
- 8.3.48
This package is auto-updated.
Last update: 2024-12-19 22:40:25 UTC
README
Set of 35 custom PHPStan rules that check architecture, typos, class namespace locations, accidental visibility override and more. Useful for any type of PHP project, from legacy to modern stack.
Install
composer require symplify/phpstan-rules --dev
Note: Make sure you use phpstan/extension-installer
to load necessary service configs.
Usage
Later, once you have most rules applied, it's best practice to include whole sets:
includes: - vendor/symplify/phpstan-rules/config/code-complexity-rules.neon - vendor/symplify/phpstan-rules/config/configurable-rules.neon - vendor/symplify/phpstan-rules/config/naming-rules.neon - vendor/symplify/phpstan-rules/config/static-rules.neon # project specific - vendor/symplify/phpstan-rules/config/rector-rules.neon - vendor/symplify/phpstan-rules/config/doctrine-rules.neon - vendor/symplify/phpstan-rules/config/symfony-rules.neon
But at start, make baby steps with one rule at a time:
CheckRequiredInterfaceInContractNamespaceRule
Interface must be located in "Contract" or "Contracts" namespace
rules: - Symplify\PHPStanRules\Rules\CheckRequiredInterfaceInContractNamespaceRule
namespace App\Repository; interface ProductRepositoryInterface { }
❌
namespace App\Contract\Repository; interface ProductRepositoryInterface { }
👍
ClassNameRespectsParentSuffixRule
Class should have suffix "%s" to respect parent type
🔧 configure it!
services: - class: Symplify\PHPStanRules\Rules\ClassNameRespectsParentSuffixRule tags: [phpstan.rules.rule] arguments: parentClasses: - Symfony\Component\Console\Command\Command
↓
class Some extends Command { }
❌
class SomeCommand extends Command { }
👍
NoConstructorOverrideRule
Possible __construct() override, this can cause missing dependencies or setup
rules: - Symplify\PHPStanRules\Rules\NoConstructorOverrideRule
class ParentClass { public function __construct(private string $dependency) { } } class SomeClass extends ParentClass { public function __construct() { } }
❌
final class SomeClass extends ParentClass { public function __construct(private string $dependency) { } }
👍
ExplicitClassPrefixSuffixRule
Interface have suffix of "Interface", trait have "Trait" suffix exclusively
rules: - Symplify\PHPStanRules\Rules\Explicit\ExplicitClassPrefixSuffixRule
<?php interface NotSuffixed { } trait NotSuffixed { } abstract class NotPrefixedClass { }
❌
<?php interface SuffixedInterface { } trait SuffixedTrait { } abstract class AbstractClass { }
👍
ForbiddenArrayMethodCallRule
Array method calls [$this, "method"] are not allowed. Use explicit method instead to help PhpStorm, PHPStan and Rector understand your code
rules: - Symplify\PHPStanRules\Rules\Complexity\ForbiddenArrayMethodCallRule
usort($items, [$this, "method"]);
❌
usort($items, function (array $apples) { return $this->method($apples); };
👍
ForbiddenExtendOfNonAbstractClassRule
Only abstract classes can be extended
rules: - Symplify\PHPStanRules\Rules\ForbiddenExtendOfNonAbstractClassRule
final class SomeClass extends ParentClass { } class ParentClass { }
❌
abstract class ParentClass { }
👍
ForbiddenFuncCallRule
Function "%s()"
cannot be used/left in the code
🔧 configure it!
services: - class: Symplify\PHPStanRules\Rules\ForbiddenFuncCallRule tags: [phpstan.rules.rule] arguments: forbiddenFunctions: - dump # or with custom error message dump: 'seems you missed some debugging function'
↓
dump('...');
❌
echo '...';
👍
ForbiddenMultipleClassLikeInOneFileRule
Multiple class/interface/trait is not allowed in single file
rules: - Symplify\PHPStanRules\Rules\ForbiddenMultipleClassLikeInOneFileRule
// src/SomeClass.php class SomeClass { } interface SomeInterface { }
❌
// src/SomeClass.php class SomeClass { } // src/SomeInterface.php interface SomeInterface { }
👍
ForbiddenNodeRule
"%s" is forbidden to use
🔧 configure it!
services: - class: Symplify\PHPStanRules\Rules\ForbiddenNodeRule tags: [phpstan.rules.rule] arguments: forbiddenNodes: - PhpParser\Node\Expr\ErrorSuppress
↓
return @strlen('...');
❌
return strlen('...');
👍
ForbiddenStaticClassConstFetchRule
Avoid static access of constants, as they can change value. Use interface and contract method instead
rules: - Symplify\PHPStanRules\Rules\ForbiddenStaticClassConstFetchRule
class SomeClass { public function run() { return static::SOME_CONST; } }
❌
class SomeClass { public function run() { return self::SOME_CONST; } }
👍
NoDynamicNameRule
Use explicit names over dynamic ones
rules: - Symplify\PHPStanRules\Rules\NoDynamicNameRule
class SomeClass { public function old(): bool { return $this->${variable}; } }
❌
class SomeClass { public function old(): bool { return $this->specificMethodName(); } }
👍
NoEntityOutsideEntityNamespaceRule
Class with #[Entity] attribute must be located in "Entity" namespace to be loaded by Doctrine
rules: - Symplify\PHPStanRules\Rules\NoEntityOutsideEntityNamespaceRule
namespace App\ValueObject; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Product { }
❌
namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Product { }
👍
NoGlobalConstRule
Global constants are forbidden. Use enum-like class list instead
rules: - Symplify\PHPStanRules\Rules\NoGlobalConstRule
const SOME_GLOBAL_CONST = 'value';
❌
class SomeClass { public function run() { return self::SOME_CONST; } }
👍
NoReferenceRule
Use explicit return value over magic &reference
rules: - Symplify\PHPStanRules\Rules\NoReferenceRule
class SomeClass { public function run(&$value) { } }
❌
class SomeClass { public function run($value) { return $value; } }
👍
NoReturnSetterMethodRule
Setter method cannot return anything, only set value
rules: - Symplify\PHPStanRules\Rules\NoReturnSetterMethodRule
final class SomeClass { private $name; public function setName(string $name): int { return 1000; } }
❌
final class SomeClass { private $name; public function setName(string $name): void { $this->name = $name; } }
👍
NoTestMocksRule
Mocking "%s" class is forbidden. Use direct/anonymous class instead for better static analysis
rules: - Symplify\PHPStanRules\Rules\PHPUnit\NoTestMocksRule
use PHPUnit\Framework\TestCase; final class SkipApiMock extends TestCase { public function test() { $someTypeMock = $this->createMock(SomeType::class); } }
❌
use PHPUnit\Framework\TestCase; final class SkipApiMock extends TestCase { public function test() { $someTypeMock = new class() implements SomeType {}; } }
👍
PreferredClassRule
Instead of "%s" class/interface use "%s"
🔧 configure it!
services: - class: Symplify\PHPStanRules\Rules\PreferredClassRule tags: [phpstan.rules.rule] arguments: oldToPreferredClasses: SplFileInfo: CustomFileInfo
↓
class SomeClass { public function run() { return new SplFileInfo('...'); } }
❌
class SomeClass { public function run() { return new CustomFileInfo('...'); } }
👍
PreventParentMethodVisibilityOverrideRule
Change "%s()"
method visibility to "%s" to respect parent method visibility.
rules: - Symplify\PHPStanRules\Rules\PreventParentMethodVisibilityOverrideRule
class SomeParentClass { public function run() { } } class SomeClass extends SomeParentClass { protected function run() { } }
❌
class SomeParentClass { public function run() { } } class SomeClass extends SomeParentClass { public function run() { } }
👍
RequireAttributeNameRule
Attribute must have all names explicitly defined
rules: - Symplify\PHPStanRules\Rules\RequireAttributeNameRule
use Symfony\Component\Routing\Annotation\Route; class SomeController { #[Route("/path")] public function someAction() { } }
❌
use Symfony\Component\Routing\Annotation\Route; class SomeController { #[Route(path: "/path")] public function someAction() { } }
👍
RequireAttributeNamespaceRule
Attribute must be located in "Attribute" namespace
rules: - Symplify\PHPStanRules\Rules\Domain\RequireAttributeNamespaceRule
// app/Entity/SomeAttribute.php namespace App\Controller; #[\Attribute] final class SomeAttribute { }
❌
// app/Attribute/SomeAttribute.php namespace App\Attribute; #[\Attribute] final class SomeAttribute { }
👍
RequireExceptionNamespaceRule
Exception
must be located in "Exception" namespace
rules: - Symplify\PHPStanRules\Rules\Domain\RequireExceptionNamespaceRule
// app/Controller/SomeException.php namespace App\Controller; final class SomeException extends Exception { }
❌
// app/Exception/SomeException.php namespace App\Exception; final class SomeException extends Exception { }
👍
RequireUniqueEnumConstantRule
Enum constants "%s" are duplicated. Make them unique instead
rules: - Symplify\PHPStanRules\Rules\Enum\RequireUniqueEnumConstantRule
use MyCLabs\Enum\Enum; class SomeClass extends Enum { private const YES = 'yes'; private const NO = 'yes'; }
❌
use MyCLabs\Enum\Enum; class SomeClass extends Enum { private const YES = 'yes'; private const NO = 'no'; }
👍
SeeAnnotationToTestRule
Class "%s" is missing @see
annotation with test case class reference
🔧 configure it!
services: - class: Symplify\PHPStanRules\Rules\SeeAnnotationToTestRule tags: [phpstan.rules.rule] arguments: requiredSeeTypes: - Rule
↓
class SomeClass extends Rule { }
❌
/** * @see SomeClassTest */ class SomeClass extends Rule { }
👍
UppercaseConstantRule
Constant "%s" must be uppercase
rules: - Symplify\PHPStanRules\Rules\UppercaseConstantRule
final class SomeClass { public const some = 'value'; }
❌
final class SomeClass { public const SOME = 'value'; }
👍
2. Doctrine-specific Rules
NoGetRepositoryOutsideServiceRule
Instead of getting repository from EntityManager, use constructor injection and service pattern to keep code clean
rules: - Symplify\PHPStanRules\Rules\Doctrine\NoGetRepositoryOutsideServiceRule
class SomeClass { public function run(EntityManagerInterface $entityManager) { return $entityManager->getRepository(SomeEntity::class); } }
❌
class SomeClass { public function __construct(SomeEntityRepository $someEntityRepository) { } }
👍
NoParentRepositoryRule
Repository should not extend parent repository, as it can lead to tight coupling
rules: - Symplify\PHPStanRules\Rules\Doctrine\NoParentRepositoryRule
use Doctrine\ORM\EntityRepository; final class SomeRepository extends EntityRepository { }
❌
final class SomeRepository { public function __construct(EntityManagerInterface $entityManager) { $this->repository = $entityManager->getRepository(SomeEntity::class); } }
👍
NoRepositoryCallInDataFixtureRule
Repository should not be called in data fixtures, as it can lead to tight coupling
rules: - Symplify\PHPStanRules\Rules\Doctrine\NoRepositoryCallInDataFixtureRule
use Doctrine\Common\DataFixtures\AbstractFixture; final class SomeFixture extends AbstractFixture { public function load(ObjectManager $objectManager) { $someRepository = $objectManager->getRepository(SomeEntity::class); $someEntity = $someRepository->get(1); } }
❌
use Doctrine\Common\DataFixtures\AbstractFixture; final class SomeFixture extends AbstractFixture { public function load(ObjectManager $objectManager) { $someEntity = $this->getReference('some-entity-1'); } }
👍
3. Symfony-specific Rules
NoAbstractControllerConstructorRule
Abstract controller should not have constructor, as it can lead to tight coupling. Use @required annotation instead
rules: - Symplify\PHPStanRules\Rules\Symfony\NoAbstractControllerConstructorRule
abstract class AbstractController extends Controller { public function __construct( private SomeService $someService ) { } }
❌
abstract class AbstractController extends Controller { private $someService; #[Required] public function autowireAbstractController(SomeService $someService) { $this->someService = $someService; } }
👍
NoRequiredOutsideClassRule
Symfony #[Require]/@required should be used only in classes to avoid misuse
rules: - Symplify\PHPStanRules\Rules\Symfony\NoRequiredOutsideClassRule
use Symfony\Component\DependencyInjection\Attribute\Required; trait SomeTrait { #[Required] public function autowireSomeTrait(SomeService $someService) { // ... } }
❌
abstract class SomeClass { #[Required] public function autowireSomeClass(SomeService $someService) { // ... } }
👍
SingleArgEventDispatchRule
The event dispatch() method can have only 1 arg - the event object
rules: - Symplify\PHPStanRules\Rules\Symfony\SingleArgEventDispatchRule
use Symfony\Component\EventDispatcher\EventDispatcherInterface; final class SomeClass { public function __construct( private EventDispatcherInterface $eventDispatcher ) { } public function run() { $this->eventDispatcher->dispatch('event', 'another-arg'); } }
❌
use Symfony\Component\EventDispatcher\EventDispatcherInterface; final class SomeClass { public function __construct( private EventDispatcherInterface $eventDispatcher ) { } public function run() { $this->eventDispatcher->dispatch(new EventObject()); } }
👍
NoListenerWithoutContractRule
There should be no listeners modified in config. Use EventSubscriberInterface contract and PHP instead
rules: - Symplify\PHPStanRules\Rules\Symfony\NoListenerWithoutContractRule
class SomeListener { public function onEvent() { } }
❌
use Symfony\Component\EventDispatcher\EventSubscriberInterface; class SomeListener implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ 'event' => 'onEvent', ]; } public function onEvent() { } }
👍
NoStringInGetSubscribedEventsRule
Symfony getSubscribedEvents() method must contain only event class references, no strings
rules: - Symplify\PHPStanRules\Rules\Symfony\NoStringInGetSubscribedEventsRule
use Symfony\Component\EventDispatcher\EventSubscriberInterface; class SomeListener implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ 'event' => 'onEvent', ]; } public function onEvent() { } }
❌
use Symfony\Component\EventDispatcher\EventSubscriberInterface; class SomeListener implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ Event::class => 'onEvent', ]; } public function onEvent() { } }
👍
RequireInvokableControllerRule
Use invokable controller with __invoke() method instead of named action method
rules: - Symplify\PHPStanRules\Rules\Symfony\RequireInvokableControllerRule
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; final class SomeController extends AbstractController { #[Route()] public function someMethod() { } }
❌
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; final class SomeController extends AbstractController { #[Route()] public function __invoke() { } }
👍
4. PHPUnit-specific Rules
NoEntityMockingRule, NoDocumentMockingRule
Instead of entity or document mocking, create object directly to get better type support
rules: - Symplify\PHPStanRules\Rules\PHPUnit\NoEntityMockingRule - Symplify\PHPStanRules\Rules\PHPUnit\NoDocumentMockingRule
use PHPUnit\Framework\TestCase; final class SomeTest extends TestCase { public function test() { $someEntityMock = $this->createMock(SomeEntity::class); } }
❌
use PHPUnit\Framework\TestCase; final class SomeTest extends TestCase { public function test() { $someEntityMock = new SomeEntity(); } }
👍
NoMockOnlyTestRule
Test should have at least one non-mocked property, to test something
rules: - Symplify\PHPStanRules\Rules\PHPUnit\NoMockOnlyTestRule
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class SomeTest extends TestCase { private MockObject $firstMock; private MockObject $secondMock; public function setUp() { $this->firstMock = $this->createMock(SomeService::class); $this->secondMock = $this->createMock(AnotherService::class); } }
❌
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class SomeTest extends TestCase { private SomeService $someService; private FirstMock $firstMock; public function setUp() { $this->someService = new SomeService(); $this->firstMock = $this->createMock(AnotherService::class); } }
👍
PublicStaticDataProviderRule
PHPUnit data provider method "%s" must be public
rules: - Symplify\PHPStanRules\Rules\PHPUnit\PublicStaticDataProviderRule
use PHPUnit\Framework\TestCase; final class SomeTest extends TestCase { /** * @dataProvider dataProvider */ public function test(): array { return []; } protected function dataProvider(): array { return []; } }
❌
use PHPUnit\Framework\TestCase; final class SomeTest extends TestCase { /** * @dataProvider dataProvider */ public function test(): array { return []; } public static function dataProvider(): array { return []; } }
👍
Happy coding!