@@ -245,6 +245,7 @@ public static function getLinesToBeIgnored($filename, $cacheTokens = TRUE)
245245 * @param $filename string Filename to be checked
246246 * @param $toplevel_funcs array List of function calls at top level that are allowed (e.g. array('define'))
247247 * @param $classes array Classes that are present in file with respect of namespaces
248+ * @param $errmsg string Error message will be written to this variable if false is returned
248249 *
249250 * @return bool
250251 */
@@ -260,131 +261,152 @@ public static function canIncludeFile($filename, array $toplevel_funcs, &$classe
260261 $ state = "default " ;
261262 $ depth = 0 ; // depth of "(" or "{"
262263 $ line = 1 ;
263- $ namespace = "" ;
264+ $ namespace = "\\" ;
265+ $ classname = "" ;
264266
265267 foreach ($ tokens as $ row ) {
266- // printf("%-12s ", $state);
267268 if (is_array ($ row )) {
268269 list ($ token , $ text , $ line ) = $ row ;
269270 $ text = str_replace ("\n" , '\\n ' , $ text );
270- // echo token_name($token) . " '$text' on line $line\n";
271- if ($ token === T_WHITESPACE || $ token === T_COMMENT || $ token === T_DOC_COMMENT ) continue ;
271+ } else {
272+ $ token = $ text = $ row ;
273+ }
274+
275+ if ($ token === T_WHITESPACE || $ token === T_COMMENT || $ token === T_DOC_COMMENT ) continue ;
276+
277+ // printf("%-12s ", $state);
278+
279+ switch ($ state ) {
280+ case "funccall " :
281+ if ($ token === "( " ) $ depth ++;
282+ else if ($ token === ") " ) $ depth --;
283+ if ($ depth == 0 ) $ state = "funccall_end " ;
284+ break ;
272285
273- switch ($ state ) {
274- case "default " :
275- if ($ token !== T_OPEN_TAG ) {
276- $ errmsg = "Have something before <?php tag on line $ line " ;
286+ case "default " :
287+ if ($ token !== T_OPEN_TAG ) {
288+ $ errmsg = "Have something before <?php tag on line $ line " ;
289+ return false ;
290+ }
291+ $ state = "root " ;
292+ break ;
293+
294+ case "root " :
295+ if ($ token === T_STRING ) { // function call
296+ if (!isset ($ toplevel_funcs [$ text ])) {
297+ $ errmsg = "Forbidden top level function call: $ text(...) on line $ line " ;
277298 return false ;
278299 }
300+ $ state = "funccall " ;
301+ $ depth = 0 ;
302+ } else if ($ token === T_ABSTRACT || $ token === T_FINAL ) {
303+ continue ;
304+ } else if ($ token === T_CLASS ) {
305+ $ state = "classdef " ;
306+ $ classname = "" ;
307+ } else if ($ token === T_CLOSE_TAG ) {
308+ $ state = "default " ;
309+ } else if ($ token === T_NAMESPACE ) {
310+ $ state = "namespace " ;
311+ $ namespace = "" ;
312+ } else if ($ token === T_USE ) {
313+ $ state = "use " ;
314+ } else if ($ token === T_FUNCTION ) {
315+ $ state = "funcdef " ;
316+ } else {
317+ $ errmsg = "Disallowed top level token ' $ text' on line $ line " ;
318+ return false ;
319+ }
320+ break ;
321+
322+ case "use " :
323+ if ($ row === "; " ) $ state = "root " ;
324+ break ;
325+
326+ case "namespace " :
327+ if ($ token === "; " ) {
279328 $ state = "root " ;
280- break ;
281- case "root " :
282- if ($ token === T_STRING ) { // function call
283- if (!isset ($ toplevel_funcs [$ text ])) {
284- $ errmsg = "Forbidden top level function call: $ text(...) on line $ line " ;
285- return false ;
286- }
287- $ state = "funccall " ;
288- $ depth = 0 ;
289- } else if ($ token === T_ABSTRACT || $ token === T_FINAL ) {
290- continue ;
291- } else if ($ token === T_CLASS ) {
292- $ state = "classdef " ;
293- } else if ($ token === T_CLOSE_TAG ) {
294- $ state = "default " ;
295- } else if ($ token === T_NAMESPACE ) {
296- $ state = "namespace " ;
297- $ namespace = "" ;
298- } else if ($ token === T_USE ) {
299- $ state = "use " ;
300- } else if ($ token === T_FUNCTION ) {
301- $ state = "funcdef " ;
302- } else {
303- $ errmsg = "Disallowed top level token " . token_name ($ token ) . " ( $ text) on line $ line " ;
329+ } else if ($ token === T_NS_SEPARATOR || $ token === T_STRING ) {
330+ $ namespace .= $ text ;
331+ } else {
332+ $ errmsg = "Unexpected token ' $ row' on line $ line (expected ';') " ;
333+ return false ;
334+ }
335+ break ;
336+
337+ case "classdef " :
338+ case "extends " :
339+ case "implements " :
340+ if ($ token === T_EXTENDS || $ token === T_IMPLEMENTS || $ token === "{ " ) {
341+ if (!$ classname ) {
342+ $ errmsg = "Empty classname on line $ line " ;
304343 return false ;
305344 }
306- break ;
307- case "namespace " :
308- $ namespace .= $ text ;
309- break ;
310- case "classdef " :
311- if ($ token === T_EXTENDS ) {
312- $ state = "extends " ;
313- } else if ($ token === T_IMPLEMENTS ) {
314- $ state = "implements " ;
315- } else if ($ token === T_STRING ) {
316- $ classname = $ namespace . "\\" . $ text ;
345+
346+ if ($ classname [0 ] != '\\' ) {
347+ $ classname = rtrim ($ namespace , "\\" ) . "\\" . $ classname ;
348+ }
349+
350+ if ($ state == "classdef " ) {
317351 if (class_exists ($ classname )) {
318352 $ errmsg = "Class ' $ classname' already exists on line $ line " ;
319353 return false ;
320- } else {
321- $ classes [] = $ classname ;
322354 }
323- } else {
324- $ errmsg = "Unexpected token " . token_name ($ token ) . " ( $ text) on line $ line " ;
325- return false ;
355+ $ classes [] = $ classname ;
326356 }
327- break ;
328- case "funccall_end " :
329- $ errmsg = "Unexpected terminator for function call: " . token_name ($ token ) . " ( $ text) on line $ line " ;
330- return false ;
331- }
332357
333- } else {
334- // echo "$row\n";
335- switch ($ state ) {
336- case "funccall " :
337- if ($ row === "( " ) $ depth ++;
338- else if ($ row === ") " ) $ depth --;
339- if ($ depth == 0 ) $ state = "funccall_end " ;
340- break ;
341- case "funccall_end " :
342- if ($ row !== "; " ) {
343- $ errmsg = "Unexpected terminator for function call: ' $ row' on line $ line " ;
344- return false ;
345- }
346- $ state = "root " ;
347- break ;
348- case "namespace " :
349- if ($ row === "; " ) {
350- $ state = "root " ;
351- } else {
352- $ errmsg = "Unexpected token ' $ row' on line $ line (expected ';') " ;
353- return false ;
358+ if ($ state != "classdef " ) {
359+ $ func = ($ state == "extends " ? "class_exists " : "interface_exists " );
360+ if (!$ func ($ classname , true )) {
361+ $ errmsg = "Class ' $ classname' does not exist on line $ line " ;
362+ return false ;
363+ }
354364 }
355- break ;
356- case "use " :
357- if ($ row === "; " ) $ state = "root " ;
358- break ;
359- case "classdef " :
360- case "extends " :
361- case "implements " :
362- if ($ row === "{ " ) {
365+
366+ if ($ token === "{ " ) {
363367 $ state = "class " ;
364368 $ depth = 1 ;
365369 } else {
366- $ errmsg = "Unexpected token ' $ row' on line $ line (expected '{') " ;
367- return false ;
368- }
369- break ;
370- case "funcdef " :
371- if ($ row === "{ " ) {
372- $ state = "function " ;
373- $ depth = 1 ;
370+ $ state = ($ token == T_EXTENDS ? "extends " : "implements " );
371+ $ classname = "" ;
374372 }
375- break ;
376- case "function " :
377- if ($ row === "{ " ) $ depth ++;
378- else if ($ row === "} " ) $ depth --;
379- if ($ depth == 0 ) $ state = "root " ;
380- break ;
381- case "class " :
382- if ($ row === "{ " ) $ depth ++;
383- else if ($ row === "} " ) $ depth --;
384- if ($ depth == 0 ) $ state = "root " ;
385- break ;
386- }
373+ } else if ($ token === T_STRING || $ token == T_NS_SEPARATOR ) {
374+ $ classname .= $ text ;
375+ } else {
376+ $ errmsg = "Unexpected token ' $ text' on line $ line (expected '{') " ;
377+ return false ;
378+ }
379+ break ;
380+
381+ case "funccall_end " :
382+ if ($ token !== "; " ) {
383+ $ errmsg = "Unexpected terminator for function call: ' $ text' on line $ line " ;
384+ return false ;
385+ }
386+ $ state = "root " ;
387+ break ;
388+
389+ case "funcdef " :
390+ if ($ row === "{ " ) {
391+ $ state = "function " ;
392+ $ depth = 1 ;
393+ }
394+ break ;
395+
396+ case "function " :
397+ if ($ token === "{ " ) $ depth ++;
398+ else if ($ token === "} " ) $ depth --;
399+ if ($ depth == 0 ) $ state = "root " ;
400+ break ;
401+
402+ case "class " :
403+ if ($ token === "{ " ) $ depth ++;
404+ else if ($ token === "} " ) $ depth --;
405+ if ($ depth == 0 ) $ state = "root " ;
406+ break ;
387407 }
408+
409+ // printf(" => %-15s %-30s %-50s line %d\n", $state, is_int($token) ? token_name($token) : $text, $text, $line);
388410 }
389411
390412 return true ;
0 commit comments