Completed
Push — master ( a32632...c637b7 )
by Juliette
9s
created

RequiredOptionalFunctionParametersSniff::process()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 45
Code Lines 26

Duplication

Lines 45
Ratio 100 %

Importance

Changes 0
Metric Value
dl 45
loc 45
rs 8.439
c 0
b 0
f 0
cc 6
eloc 26
nc 6
nop 2
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 extends PHPCompatibility_AbstractComplexVersionSniff
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
{
19
20
    /**
21
     * A list of function parameters, which were required in older versions and became optional later on.
22
     *
23
     * The array lists : version number with true (required) and false (optional).
24
     *
25
     * The index is the location of the parameter in the parameter list, starting at 0 !
26
     * If's sufficient to list the last version in which the parameter was still required.
27
     *
28
     * @var array
29
     */
30
    protected $functionParameters = array(
31
                                     'preg_match_all' => array(
32
                                         2 => array(
33
                                             'name' => 'matches',
34
                                             '5.3' => true,
35
                                             '5.4' => false,
36
                                         ),
37
                                     ),
38
                                     'stream_socket_enable_crypto' => array(
39
                                         2 => array(
40
                                             'name' => 'crypto_type',
41
                                             '5.5' => true,
42
                                             '5.6' => false,
43
                                         ),
44
                                     ),
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
        // Handle case-insensitivity of function names.
56
        $this->functionParameters = $this->arrayKeysToLowercase($this->functionParameters);
57
58
        return array(T_STRING);
59
    }//end register()
60
61
    /**
62
     * Processes this test, when one of its tokens is encountered.
63
     *
64
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
65
     * @param int                  $stackPtr  The position of the current token in
66
     *                                        the stack passed in $tokens.
67
     *
68
     * @return void
69
     */
70 View Code Duplication
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
71
    {
72
        $tokens = $phpcsFile->getTokens();
73
74
        $ignore = array(
75
                T_DOUBLE_COLON,
76
                T_OBJECT_OPERATOR,
77
                T_FUNCTION,
78
                T_CONST,
79
        );
80
81
        $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
82
        if (in_array($tokens[$prevToken]['code'], $ignore) === true) {
83
            // Not a call to a PHP function.
84
            return;
85
        }
86
87
        $function   = $tokens[$stackPtr]['content'];
88
        $functionLc = strtolower($function);
89
90
        if (isset($this->functionParameters[$functionLc]) === false) {
91
            return;
92
        }
93
94
        $parameterCount = $this->getFunctionCallParameterCount($phpcsFile, $stackPtr);
95
        if ($parameterCount === 0) {
96
            return;
97
        }
98
99
        // If the parameter count returned > 0, we know there will be valid open parenthesis.
100
        $openParenthesis      = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
101
        $parameterOffsetFound = $parameterCount - 1;
102
103
        foreach($this->functionParameters[$functionLc] as $offset => $parameterDetails) {
104
            if ($offset > $parameterOffsetFound) {
105
                $itemInfo = array(
106
                    'name'   => $function,
107
                    'nameLc' => $functionLc,
108
                    'offset' => $offset,
109
                );
110
                $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 100 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...
111
            }
112
        }
113
114
    }//end process()
115
116
117
    /**
118
     * Determine whether an error/warning should be thrown for an item based on collected information.
119
     *
120
     * @param array $errorInfo Detail information about an item.
121
     *
122
     * @return bool
123
     */
124
    protected function shouldThrowError(array $errorInfo)
125
    {
126
        return ($errorInfo['requiredVersion'] !== '');
127
    }
128
129
130
    /**
131
     * Get the relevant sub-array for a specific item from a multi-dimensional array.
132
     *
133
     * @param array $itemInfo Base information about the item.
134
     *
135
     * @return array Version and other information about the item.
136
     */
137
    public function getItemArray(array $itemInfo)
138
    {
139
        return $this->functionParameters[$itemInfo['nameLc']][$itemInfo['offset']];
140
    }
141
142
143
    /**
144
     * Get an array of the non-PHP-version array keys used in a sub-array.
145
     *
146
     * @return array
147
     */
148
    protected function getNonVersionArrayKeys()
149
    {
150
        return array('name');
151
    }
152
153
154
    /**
155
     * Retrieve the relevant detail (version) information for use in an error message.
156
     *
157
     * @param array $itemArray Version and other information about the item.
158
     * @param array $itemInfo  Base information about the item.
159
     *
160
     * @return array
161
     */
162
    public function getErrorInfo(array $itemArray, array $itemInfo)
163
    {
164
        $errorInfo = array(
165
            'paramName'       => '',
166
            'requiredVersion' => '',
167
        );
168
169
        $versionArray = $this->getVersionArray($itemArray);
170
171 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...
172
            if ($version !== 'name' && $required === true && $this->supportsBelow($version) === true) {
173
                $errorInfo['requiredVersion'] = $version;
174
            }
175
        }
176
177
        $errorInfo['paramName'] = $itemArray['name'];
178
179
        return $errorInfo;
180
181
    }//end getErrorInfo()
182
183
184
    /**
185
     * Get the error message template for this sniff.
186
     *
187
     * @return string
188
     */
189
    protected function getErrorMsgTemplate()
190
    {
191
        return 'The "%s" parameter for function %s is missing, but was required for PHP version %s and lower';
192
    }
193
194
195
    /**
196
     * Generates the error or warning for this item.
197
     *
198
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
199
     * @param int                  $stackPtr  The position of the relevant token in
200
     *                                        the stack.
201
     * @param array                $itemInfo  Base information about the item.
202
     * @param array                $errorInfo Array with detail (version) information
203
     *                                        relevant to the item.
204
     *
205
     * @return void
206
     */
207
    public function addError(PHP_CodeSniffer_File $phpcsFile, $stackPtr, array $itemInfo, array $errorInfo)
208
    {
209
        $error     = $this->getErrorMsgTemplate();
210
        $errorCode = $this->stringToErrorCode($itemInfo['name'].'_'.$errorInfo['paramName']).'Missing';
211
        $data      = array(
212
            $errorInfo['paramName'],
213
            $itemInfo['name'],
214
            $errorInfo['requiredVersion'],
215
        );
216
217
        $phpcsFile->addError($error, $stackPtr, $errorCode, $data);
218
219
    }//end addError()
220
221
222
}//end class
223