@@ -46,20 +46,29 @@ class DynamicCallsSniff extends Sniff {
4646 ];
4747
4848 /**
49- * Array of variable assignments encountered, along with their values .
49+ * Potential end tokens for which the end pointer has to be set back by one .
5050 *
51- * Populated at run-time.
51+ * {@internal The PHPCS `findEndOfStatement()` method is not completely consistent
52+ * in how it returns the statement end. This is just a simple way to bypass
53+ * the inconsistency for our purposes.}
5254 *
53- * @var array<string, string> The key is the name of the variable, the value, its assigned value.
55+ * @var array<int| string, true>
5456 */
55- private $ variables_arr = [];
57+ private $ inclusiveStopPoints = [
58+ T_COLON => true ,
59+ T_COMMA => true ,
60+ T_DOUBLE_ARROW => true ,
61+ T_SEMICOLON => true ,
62+ ];
5663
5764 /**
58- * The position in the stack where the token was found.
65+ * Array of variable assignments encountered, along with their values.
66+ *
67+ * Populated at run-time.
5968 *
60- * @var int
69+ * @var array<string, string> The key is the name of the variable, the value, its assigned value.
6170 */
62- private $ stackPtr ;
71+ private $ variables_arr = [] ;
6372
6473 /**
6574 * Returns the token types that this sniff is interested in.
@@ -78,49 +87,44 @@ public function register() {
7887 * @return void
7988 */
8089 public function process_token ( $ stackPtr ) {
81- $ this ->stackPtr = $ stackPtr ;
82-
8390 // First collect all variables encountered and their values.
84- $ this ->collect_variables ();
91+ $ this ->collect_variables ( $ stackPtr );
8592
8693 // Then find all dynamic calls, and report them.
87- $ this ->find_dynamic_calls ();
94+ $ this ->find_dynamic_calls ( $ stackPtr );
8895 }
8996
9097 /**
9198 * Finds any variable-definitions in the file being processed and stores them
9299 * internally in a private array.
93100 *
101+ * @param int $stackPtr The position in the stack where the token was found.
102+ *
94103 * @return void
95104 */
96- private function collect_variables () {
105+ private function collect_variables ( $ stackPtr ) {
97106
98- $ current_var_name = $ this ->tokens [ $ this -> stackPtr ]['content ' ];
107+ $ current_var_name = $ this ->tokens [ $ stackPtr ]['content ' ];
99108
100109 /*
101110 * Find assignments ( $foo = "bar"; ) by finding all non-whitespaces,
102111 * and checking if the first one is T_EQUAL.
103112 */
104- $ t_item_key = $ this ->phpcsFile ->findNext (
105- Tokens::$ emptyTokens ,
106- $ this ->stackPtr + 1 ,
107- null ,
108- true ,
109- null ,
110- true
111- );
112-
113+ $ t_item_key = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , $ stackPtr + 1 , null , true );
113114 if ( $ t_item_key === false || $ this ->tokens [ $ t_item_key ]['code ' ] !== T_EQUAL ) {
114115 return ;
115116 }
116117
117118 /*
118119 * Find assignments which only assign a plain text string.
119120 */
120- $ end_of_statement = $ this ->phpcsFile ->findNext ( [ T_SEMICOLON , T_CLOSE_TAG ], ( $ t_item_key + 1 ) );
121- $ value_ptr = null ;
121+ $ end_of_statement = $ this ->phpcsFile ->findEndOfStatement ( ( $ t_item_key + 1 ) );
122+ if ( isset ( $ this ->inclusiveStopPoints [ $ this ->tokens [ $ end_of_statement ]['code ' ] ] ) === true ) {
123+ --$ end_of_statement ;
124+ }
122125
123- for ( $ i = $ t_item_key + 1 ; $ i < $ end_of_statement ; $ i ++ ) {
126+ $ value_ptr = null ;
127+ for ( $ i = $ t_item_key + 1 ; $ i <= $ end_of_statement ; $ i ++ ) {
124128 if ( isset ( Tokens::$ emptyTokens [ $ this ->tokens [ $ i ]['code ' ] ] ) === true ) {
125129 continue ;
126130 }
@@ -160,9 +164,11 @@ private function collect_variables() {
160164 *
161165 * Report on this when found, using the name of the function in the message.
162166 *
167+ * @param int $stackPtr The position in the stack where the token was found.
168+ *
163169 * @return void
164170 */
165- private function find_dynamic_calls () {
171+ private function find_dynamic_calls ( $ stackPtr ) {
166172 // No variables detected; no basis for doing anything.
167173 if ( empty ( $ this ->variables_arr ) ) {
168174 return ;
@@ -172,20 +178,20 @@ private function find_dynamic_calls() {
172178 * If variable is not found in our registry of variables, do nothing, as we cannot be
173179 * sure that the function being called is one of the disallowed ones.
174180 */
175- if ( ! isset ( $ this ->variables_arr [ $ this ->tokens [ $ this -> stackPtr ]['content ' ] ] ) ) {
181+ if ( ! isset ( $ this ->variables_arr [ $ this ->tokens [ $ stackPtr ]['content ' ] ] ) ) {
176182 return ;
177183 }
178184
179185 /*
180186 * Check if we have an '(' next.
181187 */
182- $ next = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , ( $ this -> stackPtr + 1 ), null , true );
188+ $ next = $ this ->phpcsFile ->findNext ( Tokens::$ emptyTokens , ( $ stackPtr + 1 ), null , true );
183189 if ( $ next === false || $ this ->tokens [ $ next ]['code ' ] !== T_OPEN_PARENTHESIS ) {
184190 return ;
185191 }
186192
187193 $ message = 'Dynamic calling is not recommended in the case of %s(). ' ;
188- $ data = [ $ this ->variables_arr [ $ this ->tokens [ $ this -> stackPtr ]['content ' ] ] ];
189- $ this ->phpcsFile ->addError ( $ message , $ this -> stackPtr , 'DynamicCalls ' , $ data );
194+ $ data = [ $ this ->variables_arr [ $ this ->tokens [ $ stackPtr ]['content ' ] ] ];
195+ $ this ->phpcsFile ->addError ( $ message , $ stackPtr , 'DynamicCalls ' , $ data );
190196 }
191197}
0 commit comments