Completed
Push — master ( 57e842...bf9073 )
by Wim
07:35 queued 05:33
created

ArgumentFunctionsUsageSniff::process()   D

Complexity

Conditions 16
Paths 28

Size

Total Lines 94
Code Lines 51

Duplication

Lines 7
Ratio 7.45 %

Importance

Changes 0
Metric Value
dl 7
loc 94
rs 4.8736
c 0
b 0
f 0
cc 16
eloc 51
nc 28
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * \PHPCompatibility\Sniffs\PHP\ArgumentFunctionsUsageSniff.
4
 *
5
 * PHP version 5.3
6
 *
7
 * @category PHP
8
 * @package  PHPCompatibility
9
 * @author   Juliette Reinders Folmer <[email protected]>
10
 */
11
12
namespace PHPCompatibility\Sniffs\PHP;
13
14
use PHPCompatibility\Sniff;
15
16
/**
17
 * \PHPCompatibility\Sniffs\PHP\ArgumentFunctionsUsageSniff.
18
 *
19
 * - Prior to PHP 5.3, these functions could not be used as a function call parameter.
20
 *
21
 * - Calling these functions from the outermost scope of a file which has been included by
22
 *   calling `include` or `require` from within a function in the calling file, worked
23
 *   prior to PHP 5.3. As of PHP 5.3, this will generate a warning and will always return false/-1.
24
 *   If the file was called directly or included in the global scope, calls to these
25
 *   functions would already generate a warning prior to PHP 5.3.
26
 *
27
 * PHP version 5.3
28
 *
29
 * @category PHP
30
 * @package  PHPCompatibility
31
 * @author   Juliette Reinders Folmer <[email protected]>
32
 */
33
class ArgumentFunctionsUsageSniff extends Sniff
34
{
35
36
    /**
37
     * The target functions for this sniff.
38
     *
39
     * @var array
40
     */
41
    protected $targetFunctions = array(
42
        'func_get_args' => true,
43
        'func_get_arg'  => true,
44
        'func_num_args' => true,
45
    );
46
47
48
    /**
49
     * Returns an array of tokens this test wants to listen for.
50
     *
51
     * @return array
52
     */
53
    public function register()
54
    {
55
        return array(T_STRING);
56
    }
57
58
59
    /**
60
     * Processes this test, when one of its tokens is encountered.
61
     *
62
     * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
63
     * @param int                   $stackPtr  The position of the current token in the
64
     *                                         stack passed in $tokens.
65
     *
66
     * @return void
67
     */
68
    public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPtr)
69
    {
70
        $tokens     = $phpcsFile->getTokens();
71
        $functionLc = strtolower($tokens[$stackPtr]['content']);
72
        if (isset($this->targetFunctions[$functionLc]) === false) {
73
            return;
74
        }
75
76
        // Next non-empty token should be the open parenthesis.
77
        $nextNonEmpty = $phpcsFile->findNext(\PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true, null, true);
78
        if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== T_OPEN_PARENTHESIS) {
79
            return;
80
        }
81
82
        $ignore = array(
83
            T_DOUBLE_COLON    => true,
84
            T_OBJECT_OPERATOR => true,
85
            T_FUNCTION        => true,
86
            T_NEW             => true,
87
        );
88
89
        $prevNonEmpty = $phpcsFile->findPrevious(\PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
90 View Code Duplication
        if (isset($ignore[$tokens[$prevNonEmpty]['code']]) === true) {
91
            // Not a call to a PHP function.
92
            return;
93
        } elseif ($tokens[$prevNonEmpty]['code'] === T_NS_SEPARATOR && $tokens[$prevNonEmpty - 1]['code'] === T_STRING) {
94
            // Namespaced function.
95
            return;
96
        }
97
98
        $data = $tokens[$stackPtr]['content'];
99
100
        /*
101
         * Check for usage of the functions in the global scope.
102
         *
103
         * As PHPCS can not determine whether a file is included from within a function in
104
         * another file, so always throw a warning/error.
105
         */
106
        if ($phpcsFile->hasCondition($stackPtr, array(T_FUNCTION, T_CLOSURE)) === false) {
107
            $isError = false;
108
            $message = 'Use of %s() outside of a user-defined function is only supported if the file is included from within a user-defined function in another file prior to PHP 5.3.';
109
110
            if ($this->supportsAbove('5.3') === true) {
111
                $isError  = true;
112
                $message .= ' As of PHP 5.3, it is no longer supported at all.';
113
            }
114
115
            $this->addMessage($phpcsFile, $message, $stackPtr, $isError, 'OutsideFunctionScope', $data);
116
        }
117
118
        /*
119
         * Check for usage of the functions as a parameter in a function call.
120
         */
121
        if ($this->supportsBelow('5.2') === false) {
122
            return;
123
        }
124
125
        if (isset($tokens[$stackPtr]['nested_parenthesis']) === false) {
126
            return;
127
        }
128
129
        $throwError = false;
0 ignored issues
show
Unused Code introduced by
$throwError is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
130
131
        $closer = end($tokens[$stackPtr]['nested_parenthesis']);
132
        if (isset($tokens[$closer]['parenthesis_owner'])
133
            && $tokens[$tokens[$closer]['parenthesis_owner']]['type'] === 'T_CLOSURE'
134
        ) {
135
            $throwError = true;
136
        } else {
137
            $opener       = key($tokens[$stackPtr]['nested_parenthesis']);
138
            $prevNonEmpty = $phpcsFile->findPrevious(\PHP_CodeSniffer_Tokens::$emptyTokens, ($opener - 1), null, true);
139
            if ($tokens[$prevNonEmpty]['code'] !== T_STRING) {
140
                return;
141
            }
142
143
            $prevPrevNonEmpty = $phpcsFile->findPrevious(\PHP_CodeSniffer_Tokens::$emptyTokens, ($prevNonEmpty - 1), null, true);
144
            if ($tokens[$prevPrevNonEmpty]['code'] === T_FUNCTION) {
145
                return;
146
            }
147
148
            $throwError = true;
149
        }
150
151
        if ($throwError === false) {
152
            return;
153
        }
154
155
        $phpcsFile->addError(
156
            '%s() could not be used in parameter lists prior to PHP 5.3.',
157
            $stackPtr,
158
            'InParameterList',
159
            $data
160
        );
161
    }
162
163
}
164