Completed
Push — feature/new-reserved-function-... ( a826b6...62e1e9 )
by Juliette
01:48
created

ReservedFunctionNamesSniff   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
wmc 13
lcom 0
cbo 1
dl 0
loc 100
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 3
B processTokenWithinScope() 0 28 6
A processTokenOutsideScope() 0 21 4
1
<?php
2
/**
3
 * \PHPCompatibility\Sniffs\PHP\ReservedFunctionNamesSniff.
4
 *
5
 * @category PHP
6
 * @package  PHPCompatibility
7
 * @author   Juliette Reinders Folmer <[email protected]>
8
 */
9
10
namespace PHPCompatibility\Sniffs\PHP;
11
12
use PHPCompatibility\PHPCSHelper;
13
14
/**
15
 * \PHPCompatibility\Sniffs\PHP\ReservedFunctionNamesSniff.
16
 *
17
 * All function and method names starting with double underscore are reserved by PHP.
18
 *
19
 * {@internal Extends an upstream sniff to benefit from the properties contained therein.
20
 *            The properties are lists of valid PHP magic function and method names, which
21
 *            should be ignored for the purposes of this sniff.
22
 *            As this sniff is not PHP version specific, we don't need access to the utility
23
 *            methods in the PHPCompatibility\Sniff, so extending the upstream sniff is fine.
24
 *            As the upstream sniff checks the same (and more, but we don't need the rest),
25
 *            the logic in this sniff is largely the same as used upstream.
26
 *            Extending the upstream sniff instead of including it via the ruleset, however,
27
 *            prevents hard to debug issues of errors not being reported from the upstream sniff
28
 *            if this library is used in combination with other rulesets.}}
29
 *
30
 * @category PHP
31
 * @package  PHPCompatibility
32
 * @author   Juliette Reinders Folmer <[email protected]>
33
 */
34
class ReservedFunctionNamesSniff extends \Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff
35
{
36
37
    /**
38
     * Overload the constructor to work round various PHPCS cross-version compatibility issues.
39
     */
40
    public function __construct()
41
    {
42
        $scopeTokens = array(T_CLASS, T_INTERFACE, T_TRAIT);
43
        if (defined('T_ANON_CLASS')) {
44
            $scopeTokens[] = constant('T_ANON_CLASS');
45
        }
46
47
        // Call the grand-parent constructor directly.
48
        \PHP_CodeSniffer_Standards_AbstractScopeSniff::__construct($scopeTokens, array(T_FUNCTION), true);
49
50
        $phpcsVersion = PHPCSHelper::getVersion();
51
52
        if (version_compare($phpcsVersion, '2.0.0', '<') === true) {
53
            $this->magicMethods            = array_flip($this->magicMethods);
54
            $this->methodsDoubleUnderscore = array_flip($this->methodsDoubleUnderscore);
55
            $this->magicFunctions          = array_flip($this->magicFunctions);
56
        }
57
58
        // Make sure debuginfo is included in the array. Upstream only includes it since 2.5.1.
59
        $this->magicMethods['debuginfo'] = true;
60
61
    }
62
63
    /**
64
     * Processes the tokens within the scope.
65
     *
66
     * @param \PHP_CodeSniffer_File $phpcsFile The file being processed.
67
     * @param int                   $stackPtr  The position where this token was
68
     *                                         found.
69
     * @param int                   $currScope The position of the current scope.
70
     *
71
     * @return void
72
     */
73
    protected function processTokenWithinScope(\PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope)
74
    {
75
        $methodName = $phpcsFile->getDeclarationName($stackPtr);
76
        if ($methodName === null) {
77
            // Ignore closures.
78
            return;
79
        }
80
81
        // Is this a magic method. i.e., is prefixed with "__" ?
82
        if (preg_match('|^__[^_]|', $methodName) > 0) {
83
            $magicPart = strtolower(substr($methodName, 2));
84
            if (isset($this->magicMethods[$magicPart]) === false
85
                && isset($this->methodsDoubleUnderscore[$magicPart]) === false
86
            ) {
87
                $className = $phpcsFile->getDeclarationName($currScope);
88
                if (empty($className)) {
89
                    $className = '[anonymous class]';
90
                }
91
92
                $phpcsFile->addWarning(
93
                    'Method name "%s" is discouraged; PHP has reserved all method names with a double underscore prefix for future use.',
94
                    $stackPtr,
95
                    'MethodDoubleUnderscore',
96
                    array($className.'::'.$methodName)
97
                );
98
            }
99
        }
100
    }
101
102
    /**
103
     * Processes the tokens outside the scope.
104
     *
105
     * @param \PHP_CodeSniffer_File $phpcsFile The file being processed.
106
     * @param int                   $stackPtr  The position where this token was
107
     *                                         found.
108
     *
109
     * @return void
110
     */
111
    protected function processTokenOutsideScope(\PHP_CodeSniffer_File $phpcsFile, $stackPtr)
112
    {
113
        $functionName = $phpcsFile->getDeclarationName($stackPtr);
114
        if ($functionName === null) {
115
            // Ignore closures.
116
            return;
117
        }
118
119
        // Is this a magic function. i.e., it is prefixed with "__".
120
        if (preg_match('|^__[^_]|', $functionName) > 0) {
121
            $magicPart = strtolower(substr($functionName, 2));
122
            if (isset($this->magicFunctions[$magicPart]) === false) {
123
                $phpcsFile->addWarning(
124
                    'Function name "%s" is discouraged; PHP has reserved all method names with a double underscore prefix for future use.',
125
                    $stackPtr,
126
                    'FunctionDoubleUnderscore',
127
                    array($functionName)
128
                );
129
            }
130
        }
131
    }
132
133
}//end class
134