efabrica/phpstan-rules

0.7.1 2024-02-27 11:40 UTC

README

Extension for PHPStan is providing several services and rules to help find bugs in your applications.

PHP unit PHPStan level PHP static analysis Latest Stable Version Total Downloads

Installation

To use this extension, require it in Composer:

composer require --dev efabrica/phpstan-rules

Setup

This extension adds several rules. You can use them all by including these files in your phpstan.neon:

includes:
    - vendor/efabrica/phpstan-rules/extension.neon
    - vendor/efabrica/phpstan-rules/rules.neon

Or include just:

includes:
    - vendor/efabrica/phpstan-rules/extension.neon

and pick rules you want to use

Guzzle - ClientCallWithoutOptionRule

Finds all calls of GuzzleHttp\Client methods without some option e.g. timeout, connect_timeout

services:
    -
        factory: Efabrica\PHPStanRules\Rule\Guzzle\ClientCallWithoutOptionRule(['timeout', 'connect_timeout'])
        tags:
            - phpstan.rules.rule
use GuzzleHttp\Client;

$guzzleClient = new Client();
$guzzleClient->request('GET', 'https://example.com/api/url');

use GuzzleHttp\Client;

$guzzleClient = new Client();
$guzzleClient->request('GET', 'https://example.com/api/url', ['timeout' => 3, 'connect_timeout' => 1]);

👍

Tomaj/Nette API - InputParamNameRule

Checks if names of all input parameters. Every name has to contain only alphanumeric characters and _

services:  
    -
        factory: Efabrica\PHPStanRules\Rule\Tomaj\NetteApi\InputParamNameRule
        tags:
            - phpstan.rules.rule
use Tomaj\NetteApi\Handlers\BaseHandler;

final class SomeHandler extends BaseHandler
{
    public function params(): array
    {
        return [
            new GetInputParam('my-name')
        ];
    }
}

use Tomaj\NetteApi\Handlers\BaseHandler;

final class SomeHandler extends BaseHandler
{
    public function params(): array
    {
        return [
            new GetInputParam('my_name')
        ];
    }
}

👍

Check trait context - TraitContextRule

Checks if traits are used only in context of classes specified in them via comment @context {Type}

services:  
    -
        factory: Efabrica\PHPStanRules\Rule\General\TraitContextRule
        tags:
            - phpstan.rules.rule
/**
 * @context MyInterface
 */
trait MyTrait
{

}

final class SomeClass
{
    use MyTrait;
}

/**
 * @context MyInterface
 */
trait MyTrait
{

}

final class SomeClass implements MyInterface
{
    use MyTrait;
}

👍

Check calling method in object method

Checks if some method is not used in disabled context - specific method of object.

parameters:
    disabledMethodCalls:
        -
            context: 'WithCallInterface::checkedMethod'
            disabled: 'ClassWithDisabledMethod::disabledMethod'

services:
    -
        factory: Efabrica\PHPStanRules\Rule\General\DisableMethodCallInContextRule(%disabledMethodCalls%)
        tags:
            - phpstan.rules.rule
class ClassWithDisabledMethod implements WithDisabledMethodInterface
{
    public function disabledMethod() {} // this method shouldn't be called in WithCallInterface::checkedMethod
}
final class SomeClass implements WithCallInterface
{
    public function checkedMethod(): array
    {
        return [(new ClassWithDisabledMethod)->disabledMethod()]
    }
}

final class SomeClass implements WithCallInterface
{
    public function checkedMethod(): array
    {
        return [(new ClassWithDisabledMethod)]
    }
}

👍

Check calling method with required parameters

Checks if some method is called with all required parameters with corresponding types.

parameters:
    requiredParametersInMethodCalls:
        -
            context: 'SomeClass::someMethod'
            parameters:
                -
                    name: someParameter
                    type: string
                    tip: 'Always use parameter someParameter as string because...'

services:
    -
        factory: Efabrica\PHPStanRules\Rule\General\RequiredParametersInMethodCallRule(%requiredParametersInMethodCalls%)
        tags:
            - phpstan.rules.rule
class SomeClass
{
    public function someMethod(?string $someParameter = null): void
    {
        // this method should be called with string value of $someParameter
    }
}
class Foo
{
    public function bar(SomeClass $someClass)
    {
        $someClass->someMethod();
    }
}

class Foo
{
    public function bar(SomeClass $someClass)
    {
        $someClass->someMethod('baz');
    }
}

👍

Do not concatenate translated strings

Every language has its own word order in sentences, we can't use e.g. variables at the same place for all languages. There are mechanisms in translate libraries e.g. symfony/translator - we can use placeholders like %name% etc. This rule checks if you use translated messages and then concat them with some other strings.

parameters:
    translateCalls:
        - iAmTranslateFunction
        - Efabrica\PHPStanRules\Tests\Rule\General\DisabledConcatenationWithTranslatedStringsRule\Source\TranslatorInterface::iAmTranslateMethod
        - Efabrica\PHPStanRules\Tests\Rule\General\DisabledConcatenationWithTranslatedStringsRule\Source\TranslatorInterface::iAmTranslateStaticMethod
    allowedTranslateConcatenationPatterns:
        - '[\s]*<.*?>[\s]*<\/.*?>[\s]*'
        - '[\s]*This is allowed text[\s]*'
        - '[\s]*\#[0-9]+[\s]*'

services:
    -
        factory: Efabrica\PHPStanRules\Rule\General\DisabledConcatenationWithTranslatedStringsRule(%translateCalls%)
        tags:
            - phpstan.rules.rule
$message = 'Hello';
$name = 'Mark';
echo $translator->iAmTranslateMethod($message) . ' ' . $name;

$message = 'Hello %name%';
$name = 'Mark';
echo $translator->iAmTranslateMethod($message, ['name' => $name];

👍

Forbidden constructor parameters types

This rule checks if constructor contains forbidden parameter types.

parameters:
    forbiddenConstructorParametersTypes:
        -
            context: 'SomeClass'
            forbiddenTypes:
                -
                    type: ForbiddenType
                    tip: 'ForbiddenType is not allowed, use NotForbiddenType instead'

services:
    -
        factory: Efabrica\PHPStanRules\Rule\General\ForbiddenConstructorParametersTypesRule(%forbiddenConstructorParametersTypes%)
        tags:
            - phpstan.rules.rule
class SomeClass
{

}

class ForbiddenType
{

}

class NotForbiddenType
{

}
class Foo extends SomeClass
{
    public function __construct(ForbiddenType $type)
    {
    
    }
}

class Foo extends SomeClass
{
    public function __construct(NotForbiddenType $type)
    {
    
    }
}

👍

Performance - DisabledCallsInLoopsRule

Some functions are not recommended to be called in loops. For example array_merge.

services:
    -
        factory: Efabrica\PHPStanRules\Rule\Performance\DisabledCallsInLoopsRule
        tags:
            - phpstan.rules.rule
$result = [];
for ($i = 0; $i < 100; $i++) {
    $result = array_merge($result, $data[$i]);
}

$result = array_merge([], ...$data);

👍