Completed
Pull Request — master (#300)
by Juliette
01:50
created

PregReplaceEModifierSniff::processRegexPattern()   B

Complexity

Conditions 9
Paths 30

Size

Total Lines 56
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 56
rs 7.1584
c 0
b 0
f 0
cc 9
eloc 28
nc 30
nop 4

How to fix   Long Method   

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_PregReplaceEModifierSniff.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @category  PHP
8
 * @package   PHPCompatibility
9
 * @author    Wim Godden <[email protected]>
10
 * @copyright 2014 Cu.be Solutions bvba
11
 */
12
13
/**
14
 * PHPCompatibility_Sniffs_PHP_PregReplaceEModifierSniff.
15
 *
16
 * @category  PHP
17
 * @package   PHPCompatibility
18
 * @author    Wim Godden <[email protected]>
19
 * @version   1.1.0
20
 * @copyright 2014 Cu.be Solutions bvba
21
 */
22
class PHPCompatibility_Sniffs_PHP_PregReplaceEModifierSniff extends PHPCompatibility_Sniff
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...
23
{
24
25
    /**
26
     * Functions to check for.
27
     *
28
     * @var array
29
     */
30
    protected $functions = array(
31
        'preg_replace' => true,
32
        'preg_filter'  => true,
33
    );
34
35
    /**
36
     * Regex bracket delimiters.
37
     *
38
     * @var array
39
     */
40
    protected $doublesSeparators = array(
41
        '{' => '}',
42
        '[' => ']',
43
        '(' => ')',
44
        '<' => '>',
45
    );
46
47
    /**
48
     * Returns an array of tokens this test wants to listen for.
49
     *
50
     * @return array
51
     */
52
    public function register()
53
    {
54
        return array(T_STRING);
55
    }//end register()
56
57
    /**
58
     * Processes this test, when one of its tokens is encountered.
59
     *
60
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
61
     * @param int                  $stackPtr  The position of the current token in the
62
     *                                        stack passed in $tokens.
63
     *
64
     * @return void
65
     */
66
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
67
    {
68
        if ($this->supportsAbove('5.5') === false) {
69
            return;
70
        }
71
72
        $tokens         = $phpcsFile->getTokens();
73
        $functionName   = $tokens[$stackPtr]['content'];
74
        $functionNameLc = strtolower($functionName);
75
76
        // Bow out if not one of the functions we're targetting.
77
        if ( isset($this->functions[$functionNameLc]) === false ) {
78
            return;
79
        }
80
81
        // Get the first parameter in the function call as that should contain the regex(es).
82
        $firstParam = $this->getFunctionCallParameter($phpcsFile, $stackPtr, 1);
83
        if ($firstParam === false) {
84
            return;
85
        }
86
87
        // Differentiate between an array of patterns passed and a single pattern.
88
        $nextNonEmpty = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $firstParam['start'], ($firstParam['end'] +1), true);
89
        if ($tokens[$nextNonEmpty]['code'] === T_ARRAY) {
90
            $arrayValues = $this->getFunctionCallParameters($phpcsFile, $nextNonEmpty);
0 ignored issues
show
Security Bug introduced by
It seems like $nextNonEmpty defined by $phpcsFile->findNext(\PH...Param['end'] + 1, true) on line 88 can also be of type false; however, PHPCompatibility_Sniff::...unctionCallParameters() 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...
91
            foreach ($arrayValues as $value) {
92
                $hasKey = $phpcsFile->findNext(T_DOUBLE_ARROW, $value['start'], ($value['end'] + 1));
93
                if ($hasKey !== false) {
94
                    $value['start'] = ($hasKey + 1);
95
                    $value['raw']   = trim($phpcsFile->getTokensAsString($value['start'], (($value['end'] + 1) - $value['start'])));
96
                }
97
98
                $this->processRegexPattern($value, $phpcsFile, $value['end'], $functionName);
99
            }
100
        }
101
        else {
102
            $this->processRegexPattern($firstParam, $phpcsFile, $stackPtr, $functionName);
103
        }
104
105
    }//end process()
106
107
108
	/**
109
     * Analyse a potential regex pattern for usage of the /e modifier.
110
     *
111
     * @param array                $pattern      Array containing the start and end token
112
	 *                                           pointer of the potential regex pattern and
113
	 *                                           the raw string value of the pattern.
114
     * @param PHP_CodeSniffer_File $phpcsFile    The file being scanned.
115
     * @param int                  $stackPtr     The position of the current token in the
116
     *                                           stack passed in $tokens.
117
     * @param string               $functionName The function which contained the pattern.
118
     *
119
     * @return void
120
	 */
121
    protected function processRegexPattern($pattern, $phpcsFile, $stackPtr, $functionName)
122
    {
123
        $tokens = $phpcsFile->getTokens();
124
125
        /*
126
         * The pattern might be build up of a combination of strings, variables
127
         * and function calls. We are only concerned with the strings.
128
         */
129
        $regex = '';
130
        for ($i = $pattern['start']; $i <= $pattern['end']; $i++ ) {
131
            if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$stringTokens, true) === true) {
132
                $regex .= $this->stripQuotes($tokens[$i]['content']);
133
            }
134
        }
135
        // Deal with multi-line regexes which were broken up in several string tokens.
136
        $regex = $this->stripQuotes($regex);
137
138
        if ($regex === '') {
139
            // No string token found in the first parameter, so skip it (e.g. if variable passed in).
140
            return;
141
        }
142
143
        $regexFirstChar = substr($regex, 0, 1);
144
145
        // Make sure that the character identified as the delimiter is valid.
146
        // Otherwise, it is a false positive caused by the string concatenation.
147
        if (preg_match('`[a-z0-9\\\\ ]`i', $regexFirstChar) === 1) {
148
            return;
149
        }
150
151
        if (isset($this->doublesSeparators[$regexFirstChar])) {
152
            $regexEndPos = strrpos($regex, $this->doublesSeparators[$regexFirstChar]);
153
        }
154
        else {
155
            $regexEndPos = strrpos($regex, $regexFirstChar);
156
        }
157
158
        if($regexEndPos) {
159
            $modifiers = substr($regex, $regexEndPos + 1);
160
161
            if (strpos($modifiers, 'e') !== false) {
162
                $error     = '%s() - /e modifier is deprecated since PHP 5.5';
163
                $isError   = false;
164
                $errorCode = 'Deprecated';
165
                $data      = array($functionName);
166
167
                if ($this->supportsAbove('7.0')) {
168
                    $error    .= ' and removed since PHP 7.0';
169
                    $isError   = true;
170
                    $errorCode = 'Removed';
171
                }
172
173
                $this->addMessage($phpcsFile, $error, $stackPtr, $isError, $errorCode, $data);
174
            }
175
        }
176
    }//end processRegexPattern()
177
178
}//end class
179