Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * Generic_Sniffs_Functions_CallTimePassByReferenceSniff.
4
 *
5
 * PHP version 5
6
 *
7
 * @category  PHP
8
 * @package   PHP_CodeSniffer
9
 * @author    Florian Grandel <jerico.dev@gmail.com>
10
 * @copyright 2009 Florian Grandel
11
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
12
 * @version   CVS: $Id: OpeningFunctionBraceBsdAllmanSniff.php 259084 2008-05-05 03:59:12Z squiz $
13
 * @link      http://pear.php.net/package/PHP_CodeSniffer
14
 */
15
 
16
/**
17
 * Generic_Sniffs_Functions_CallTimePassByReferenceSniff.
18
 *
19
 * Ensures that variables are not passed by reference when calling a function.
20
 *
21
 * @category  PHP
22
 * @package   PHP_CodeSniffer
23
 * @author    Florian Grandel <jerico.dev@gmail.com>
24
 * @copyright 2009 Florian Grandel
25
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
26
 * @version   Release: 1.2.1
27
 * @link      http://pear.php.net/package/PHP_CodeSniffer
28
 */
29
class Generic_Sniffs_Functions_CallTimePassByReferenceSniff implements PHP_CodeSniffer_Sniff
30
{
31
 
32
 
33
    /**
34
     * Returns an array of tokens this test wants to listen for.
35
     *
36
     * @return array
37
     */
38
    public function register()
39
    {
40
        return array(T_STRING);
41
 
42
    }//end register()
43
 
44
 
45
    /**
46
     * Processes this test, when one of its tokens is encountered.
47
     *
48
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
49
     * @param int                  $stackPtr  The position of the current token
50
     *                                        in the stack passed in $tokens.
51
     *
52
     * @return void
53
     */
54
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
55
    {
56
        $tokens = $phpcsFile->getTokens();
57
 
58
        // Skip tokens that are the names of functions or classes
59
        // within their definitions. For example: function myFunction...
60
        // "myFunction" is T_STRING but we should skip because it is not a
61
        // function or method *call*.
62
        $functionName = $stackPtr;
63
        $findTokens   = array_merge(
64
            PHP_CodeSniffer_Tokens::$emptyTokens,
65
            array(T_BITWISE_AND)
66
        );
67
 
68
        $functionKeyword = $phpcsFile->findPrevious(
69
            $findTokens,
70
            ($stackPtr - 1),
71
            null,
72
            true
73
        );
74
 
75
        if ($tokens[$functionKeyword]['code'] === T_FUNCTION
76
            || $tokens[$functionKeyword]['code'] === T_CLASS
77
        ) {
78
            return;
79
        }
80
 
81
        // If the next non-whitespace token after the function or method call
82
        // is not an opening parenthesis then it cant really be a *call*.
83
        $openBracket = $phpcsFile->findNext(
84
            PHP_CodeSniffer_Tokens::$emptyTokens,
85
            ($functionName + 1),
86
            null,
87
            true
88
        );
89
 
90
        if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
91
            return;
92
        }
93
 
94
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
95
 
96
        $nextSeparator = $openBracket;
97
        while (($nextSeparator = $phpcsFile->findNext(T_VARIABLE, ($nextSeparator + 1), $closeBracket)) !== false) {
98
            // Make sure the variable belongs directly to this function call
99
            // and is not inside a nested function call or array.
100
            $brackets    = $tokens[$nextSeparator]['nested_parenthesis'];
101
            $lastBracket = array_pop($brackets);
102
            if ($lastBracket !== $closeBracket) {
103
                continue;
104
            }
105
 
106
            // Checking this: $value = my_function(...[*]$arg...).
107
            $tokenBefore = $phpcsFile->findPrevious(
108
                PHP_CodeSniffer_Tokens::$emptyTokens,
109
                ($nextSeparator - 1),
110
                null,
111
                true
112
            );
113
 
114
            if ($tokens[$tokenBefore]['code'] === T_BITWISE_AND) {
115
                // Checking this: $value = my_function(...[*]&$arg...).
116
                $tokenBefore = $phpcsFile->findPrevious(
117
                    PHP_CodeSniffer_Tokens::$emptyTokens,
118
                    ($tokenBefore - 1),
119
                    null,
120
                    true
121
                );
122
 
123
                // We have to exclude all uses of T_BITWISE_AND that are not
124
                // references. We use a blacklist approach as we prefer false
125
                // positives to not identifiying a pass-by-reference call at all.
126
                // The blacklist may not yet be complete.
127
                switch ($tokens[$tokenBefore]['code']) {
128
                case T_VARIABLE:
129
                case T_CLOSE_PARENTHESIS:
130
                    // In these cases T_BITWISE_AND represents
131
                    // the bitwise and operator.
132
                    continue;
133
                    break;
134
 
135
                default:
136
                    // T_BITWISE_AND represents a pass-by-reference.
137
                    $error = 'Call-time pass-by-reference calls are prohibited';
138
                    $phpcsFile->addError($error, $tokenBefore);
139
                    break;
140
                }
141
            }//end if
142
        }//end while
143
 
144
    }//end process()
145
 
146
 
147
}//end class
148
 
149
?>