Skip to content

PHP CodeSniffer sniff to enforce PHP 7 types and documentation of array variables

License

Notifications You must be signed in to change notification settings

jeroennoten/phpcs-type-sniff

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHPCS Type Sniff

Latest Version on Packagist Software License Build Status Coverage Status Quality Score Total Downloads

Custom phpcs CodeSniffer rule that:

  • Enforces usage of PHP 7 type declarations (where possible)
  • Enforces documenting array types with more specific types (e.g. int[])
  • Checks for useless PHPDoc blocks (no repeated information)
  • Many more other checks

Example PHP class (comments on the right = phpcs warnings):

<?php

namespace Fruits;

/**
 * Class Banana                     // useless description
 * @package Fruits                  // useless tag
 */
class Banana
{
    const C1 = [];                  // missing typed array doc type

    /** @var array */               // must use typed array doc type
    const C2 = [];

    /** @var array[] */             // must use specific typed array doc type
    const C3 = [[]];

    /** @var bool|false */          // redundant false type
    const C4 = false;

    /**
     * @var int                     // incompatible int type, missing null type
     */
    const C5 = null;

    /** @var int */
    const C6 = 1;                   // useless PHPDoc

    public $prop1 = [];             // missing typed array doc type

    /** @var array */               // must use typed array doc type
    public $prop2 = [];

    public $prop3;                  // missing @var tag, missing null doc type

    /** @var */                     // missing doc type, missing null doc type
    public $prop4;

    /** @var array[][] */           // must use specific typed array doc type, missing null doc type
    public $prop5;

    /** @var array|string[] */      // redundant array type, missing null doc type
    public $prop6;

    /** @var int|string */          // missing null doc type
    public $prop7 = null;

    /** @var int $prop8 */          // prop name must be removed, missing null doc type
    public $prop8;

    /** @var int */
    public $prop9;                  // Not initialized, missing null doc type

    /** @var int */
    public $prop10;                 // Initialized, missing null doc type

    /** @var int */
    public $prop11;

    /** @var int */
    public $prop12;

    public function __construct()
    {
        $this->prop10 = null;
        $this->prop11 = 11;
        $this->setProp12();
    }

    public function setProp12(): void
    {
        $this->prop12 = 1;
    }

    public function func1(
        $param1,                    // missing param type decl.
        int $param2
    ) {                             // missing return type decl.
    }

    /**
     * @param int|null  $param1
     * @param int|null  $param2
     * @param array     $param3     // must use typed array doc type
     *
     * @param           $param5     // suggested int doc type
     * @param           $param6     // missing doc type
     * @param array[]   $param7     // must use specific typed array doc type
     * @param bool|true $param8     // remove true doc type
     * @param null      $param9     // suggested compound doc type, e.g. int|null
     * @param string    $param10    // incompatible string type, missing int, null types
     * @param stdClass  $param11
     * @param bool|int  $param12
     *
     * @return void                 // useless tag
     */
    public function func2(
        $param1,                    // suggested ?int type decl.
        int $param2 = null,         // suggested ?int type decl.
        array $param3,
        $param4,                    // missing @param tag
        int $param5,
        $param6,
        array $param7,
        bool $param8,
        $param9 = null,             // missing type decl.
        ?int $param10 = null,
        stdClass $param11,
        $param12
    ): void {
    }

    /**
     * @return int
     */
    public function func3(): int    // useless PHPDoc
    {
    }

    /**
     * @param array<int, bool>           $arg1 // alternative array documentation
     * @param array{foo: bool, bar: int} $arg2 // supported, no warning
     * @param (int|string)[]             $arg3 //
     * @param array('key1' => int, ...)  $arg4 //
     */
    public function func4(
        array $arg1,
        array $arg2,
        array $arg3,
        array $arg4
    ): void {
    }
}

Install

Via Composer

$ composer require --dev gskema/phpcs-type-sniff

Usage

This is a standalone sniff file, you need to add it to your phpcs.xml file.

Usage Without Reflection

Inspections for methods with @inheritdoc tag are skipped. If a method does not have this tag, it is inspected. This is the recommend setup.

<ruleset name="your_ruleset">
    <!-- your configuration -->
    <rule ref="PSR2"/>

    <!-- phpcs-type-sniff configuration -->   
    <rule ref="./vendor/gskema/phpcs-type-sniff/src/Sniffs/CompositeCodeElementSniff.php"/>
</ruleset>

Usage With Reflection

With reflection enabled, this sniff can assert if @inheritoc tag is needed. Inspections for extended/implemented methods are skipped. Reflections need to load actual classes, which is why we need to include the autoloader. This option is good for inspecting extended methods, however using ReflectionClass may cause phpcs crashes while editing (not possible to catch FatalError).

<ruleset name="your_ruleset">
    <!-- your configuration -->
    <rule ref="PSR2"/>

    <!-- phpcs-type-sniff configuration -->   
    <arg name="bootstrap" value="./vendor/autoload.php"/>
    <rule ref="./vendor/gskema/phpcs-type-sniff/src/Sniffs/CompositeCodeElementSniff.php">
        <properties>
            <property name="useReflection" value="true"/>
        </properties>
    </rule>
</ruleset>

Configuration

Sniffs are registered and saved by their short class name. This allows easily specifying configuration options for a specific code element sniff, e.g. FqcnMethodSniff.invalidTags. All custom code sniff classes must have unique short class names.

String true/false values are automatically converted to booleans.

<ruleset name="your_ruleset">
    <!-- your configuration -->
    <rule ref="PSR2"/>

    <!-- phpcs-type-sniff configuration -->   

    <!-- Includes an autoloader which is needed when using reflection API -->
    <!-- or custom code element sniff(s) -->
    <arg name="bootstrap" value="./vendor/autoload.php"/>

    <!-- Includes a standalone sniff to your custom coding standard -->
    <rule ref="./vendor/gskema/phpcs-type-sniff/src/Sniffs/CompositeCodeElementSniff.php">
        <properties>

            <!-- Enables usage of reflection API when inspecting extended classes. -->
            <!-- Autoloader is needed. -->
            <property name="useReflection" value="true"/>

            <!-- Disables one of the default code element sniffs -->
            <property name="FqcnConstSniff.enabled" value="false" />
            <property name="FqcnMethodSniff.enabled" value="false" />
            <property name="FqcnPropSniff.enabled" value="false" />
            <property name="FqcnDescriptionSniff.enabled" value="false" />

            <!-- Tags that should be removed from method PHPDoc -->
            <property name="FqcnMethodSniff.invalidTags" type="array">
                <element value="@someTag1"/>
                <element value="@someTag2"/>
            </property>

            <!-- Description lines and tags that should be removed from FQCN PHPDoc -->
            <property name="FqcnDescriptionSniff.invalidPatterns" type="array">
                <element value="^Nothing.+Useful$"/>
            </property>
            <property name="FqcnDescriptionSniff.invalidTags" type="array">
                <element value="@api"/>
            </property>

            <!-- Disables reporting missing @param, @return tags in non-empty method PHPDoc -->
            <!-- when method type declarations are present -->
            <property name="FqcnMethodSniff.reportMissingTags" value="false"/>

            <!-- Disables reporting missing null type in basic getter return PHPDoc -->
            <!-- and return type declaration -->
            <property name="FqcnPropSniff.reportNullableBasicGetter" value="false"/>

            <!-- Disables reporting missing null type in property PHPDoc -->
            <!-- when there is no default value and no assigned value in __construct() -->
            <!--- Some false positives in exotic cases may be reported -->
            <property name="FqcnPropSniff.reportUninitializedProp" value="false"/>

            <!-- Your own custom code element sniff(s). Autoloader is needed. -->
            <!-- These classes implement CodeElementSniffInterface -->
            <property name="sniffs" type="array">
                <element value="\Acme\CustomCodeElementSniff" />
                <element value="\Acme\AnotherCustomMethodSniff" />
            </property>

            <!-- Configuration options for custom code element sniffs -->
            <property name="CustomCodeElementSniff.opt1" value="str1" />
            <!-- Specifying element key(s) will create an associative array -->
            <property name="AnotherCustomMethodSniff.arrayOpt1" type="array">
                <element key="key1" value="str1"/>
                <element key="key2" value="str2"/>
            </property>

        </properties>
    </rule>
</ruleset>

Change log

Please see CHANGELOG for more information on what has changed recently.

Testing

$ ./vendor/bin/phpunit

License

The MIT License (MIT). Please see License File for more information.

About

PHP CodeSniffer sniff to enforce PHP 7 types and documentation of array variables

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 100.0%