Completed
Pull Request — master (#291)
by Juliette
02:26
created

getItemArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff.
4
 *
5
 * @category  PHP
6
 * @package   PHPCompatibility
7
 * @author    Juliette Reinders Folmer <[email protected]>
8
 */
9
10
/**
11
 * PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff.
12
 *
13
 * @category  PHP
14
 * @package   PHPCompatibility
15
 * @author    Juliette Reinders Folmer <[email protected]>
16
 */
17
class PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
18
    extends PHPCompatibility_AbstractComplexVersionSniff
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
19
{
20
21
    /**
22
     * A list of function parameters, which were required in older versions and became optional later on.
23
     *
24
     * The array lists : version number with true (required) and false (optional).
25
     *
26
     * The index is the location of the parameter in the parameter list, starting at 0 !
27
     * If's sufficient to list the last version in which the parameter was still required.
28
     *
29
     * @var array
30
     */
31
    protected $functionParameters = array(
32
                                     'preg_match_all' => array(
33
                                         2 => array(
34
                                             'name' => 'matches',
35
                                             '5.3' => true,
36
                                             '5.4' => false,
37
                                         ),
38
                                     ),
39
                                     'stream_socket_enable_crypto' => array(
40
                                         2 => array(
41
                                             'name' => 'crypto_type',
42
                                             '5.5' => true,
43
                                             '5.6' => false,
44
                                         ),
45
                                     ),
46
                                    );
47
48
49
    /**
50
     * Returns an array of tokens this test wants to listen for.
51
     *
52
     * @return array
53
     */
54
    public function register()
55
    {
56
        // Handle case-insensitivity of function names.
57
        $this->functionParameters = $this->arrayKeysToLowercase($this->functionParameters);
58
59
        return array(T_STRING);
60
    }//end register()
61
62
    /**
63
     * Processes this test, when one of its tokens is encountered.
64
     *
65
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
66
     * @param int                  $stackPtr  The position of the current token in
67
     *                                        the stack passed in $tokens.
68
     *
69
     * @return void
70
     */
71
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
72
    {
73
        $tokens = $phpcsFile->getTokens();
74
75
        $ignore = array(
76
                T_DOUBLE_COLON,
77
                T_OBJECT_OPERATOR,
78
                T_FUNCTION,
79
                T_CONST,
80
        );
81
82
        $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
83
        if (in_array($tokens[$prevToken]['code'], $ignore) === true) {
84
            // Not a call to a PHP function.
85
            return;
86
        }
87
88
        $function   = $tokens[$stackPtr]['content'];
89
        $functionLc = strtolower($function);
90
91
        if (isset($this->functionParameters[$functionLc]) === false) {
92
            return;
93
        }
94
95
        $parameterCount = $this->getFunctionCallParameterCount($phpcsFile, $stackPtr);
96
        if ($parameterCount === 0) {
97
            return;
98
        }
99
100
        // If the parameter count returned > 0, we know there will be valid open parenthesis.
101
        $openParenthesis      = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
102
        $parameterOffsetFound = $parameterCount - 1;
103
        $requiredVersion      = null;
0 ignored issues
show
Unused Code introduced by
$requiredVersion 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...
104
        $parameterName        = null;
0 ignored issues
show
Unused Code introduced by
$parameterName 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...
105
106
        foreach($this->functionParameters[$functionLc] as $offset => $parameterDetails) {
107
            if ($offset > $parameterOffsetFound) {
108
                $itemInfo = array(
109
                    'name'   => $function,
110
                    'nameLc' => $functionLc,
111
                    'offset' => $offset,
112
                );
113
                $this->handleFeature($phpcsFile, $openParenthesis, $itemInfo);
0 ignored issues
show
Security Bug introduced by
It seems like $openParenthesis defined by $phpcsFile->findNext(\PH...null, true, null, true) on line 101 can also be of type false; however, PHPCompatibility_Abstrac...nSniff::handleFeature() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
114
            }
115
        }
116
117
    }//end process()
118
119
120
    /**
121
     * Determine whether an error/warning should be thrown for an item based on collected information.
122
     *
123
     * @param array $errorInfo Detail information about an item.
124
     *
125
     * @return bool
126
     */
127
    protected function shouldThrowError(array $errorInfo)
128
    {
129
        return ($errorInfo['requiredVersion'] !== '');
130
    }
131
132
133
    /**
134
     * Get the relevant sub-array for a specific item from a multi-dimensional array.
135
     *
136
     * @param array $itemInfo Base information about the item.
137
     *
138
     * @return array Version and other information about the item.
139
     */
140
    public function getItemArray(array $itemInfo)
141
    {
142
        return $this->functionParameters[$itemInfo['nameLc']][$itemInfo['offset']];
143
    }
144
145
146
    /**
147
     * Get an array of the non-PHP-version array keys used in a sub-array.
148
     *
149
     * @return array
150
     */
151
    protected function getNonVersionArrayKeys()
152
    {
153
        return array('name');
154
    }
155
156
157
    /**
158
     * Retrieve the relevant detail (version) information for use in an error message.
159
     *
160
     * @param array $itemArray Version and other information about the item.
161
     * @param array $itemInfo  Base information about the item.
162
     *
163
     * @return array
164
     */
165
    public function getErrorInfo(array $itemArray, array $itemInfo)
166
    {
167
        $errorInfo = array(
168
            'paramName'       => '',
169
            'requiredVersion' => '',
170
        );
171
172
        $versionArray = $this->getVersionArray($itemArray);
173
174 View Code Duplication
        foreach ($versionArray as $version => $required) {
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
            if ($version !== 'name' && $required === true && $this->supportsBelow($version) === true) {
176
                $errorInfo['requiredVersion'] = $version;
177
            }
178
        }
179
180
        $errorInfo['paramName'] = $itemArray['name'];
181
182
        return $errorInfo;
183
184
    }//end getErrorInfo()
185
186
187
    /**
188
     * Get the error message template for this sniff.
189
     *
190
     * @return string
191
     */
192
    protected function getErrorMsgTemplate()
193
    {
194
        return 'The "%s" parameter for function %s is missing, but was required for PHP version %s and lower';
195
    }
196
197
198
    /**
199
     * Generates the error or warning for this item.
200
     *
201
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
202
     * @param int                  $stackPtr  The position of the relevant token in
203
     *                                        the stack.
204
     * @param array                $itemInfo  Base information about the item.
205
     * @param array                $errorInfo Array with detail (version) information
206
     *                                        relevant to the item.
207
     *
208
     * @return void
209
     */
210
    public function addError(PHP_CodeSniffer_File $phpcsFile, $stackPtr, array $itemInfo, array $errorInfo)
211
    {
212
        $error     = $this->getErrorMsgTemplate();
213
        $errorCode = $this->stringToErrorCode($itemInfo['name'].'_'.$errorInfo['paramName']).'Missing';
214
        $data      = array(
215
            $errorInfo['paramName'],
216
            $itemInfo['name'],
217
            $errorInfo['requiredVersion'],
218
        );
219
220
        $phpcsFile->addError($error, $stackPtr, $errorCode, $data);
221
222
    }//end addError()
223
224
225
}//end class
226