2010-10-27 7 views
7

Ich bin auf der Suche nach einem regulären Ausdruck, der jede PHP-Aufrufzeit durch Referenzen im Quellcode genau identifizieren wird, um die Migration zu PHP 5.3 zu unterstützen.Regexp zur Erkennung der Anrufzeit durch Referenzen im PHP-Quellcode

Zur Zeit habe ich [^=&]\s*&\s*\$, aber dies filtert keine Zuweisungsfälle ($var = &$othervar;).

Diese Regexp sollte mit Eclipse kompatibel sein (sorry, nicht sicher, welche Art von Regexp Eclipse analysiert).

Edit: Dieses ist ein bisschen näher (obwohl ein bisschen wie ein Hack): (?<!([&=]\s{0,15}))&\s*\$

+0

Nun, es wird viel schwieriger ... Da 'Array ($ var)' ist gültig. Ich bin mir also nicht sicher, ob ein Regex es auch (zumindest einen einfachen) zuverlässig erkennen kann ... – ircmaxell

+0

Und darum habe ich die Frage gestellt ;-) – Kenaniah

Antwort

7

Sie können dafür phpcs verwenden. Es hat eine rule to detect Call Time Pass by References:

Stellt sicher, dass Variablen nicht durch Referenz beim Aufruf einer Funktion übergeben werden.

Es gibt auch eine plugin to integrate phpcs into Eclipse

rulesets für PHPCS generieren (und PMD) ist einfach, mit diesem Online-Generator:

+0

Dank für den Link, Gordon, aber ich suche wirklich nach einer Regexp. Diese Codebasis hat buchstäblich Hunderte von Quelldateien – Kenaniah

+3

+1: Eine vorgefertigte Lösung ist am besten ... @Kenaniah: 'phpcs' ist ein Scanner, der buchstäblich Hunderte von Quelldateien scannt und einen Bericht von dem, was er gefunden hat, ausgibt was du suchst ... – ircmaxell

+0

Ich gebe es eine Chance, da es ein Eclipse-Plugin dafür gibt. – Kenaniah

3

Sie können nicht diejenigen mit regex bekommen. Verwenden Sie stattdessen die Tokenizer. Sie müssen nach '&' suchen, wobei dem nächsten '(' auf der linken Seite (Klammern beim Gehen dort auflösen) T_STRING vorangestellt ist, aber nicht T_FUNCTION.

$tokens = new TokenStream($source); 
foreach ($tokens as $i => $token) { 
    if ($token->is(T_AMP)) { 
     while ($i--) { 
      if ($tokens[$i]->is(T_CLOSE_ROUND, T_CLOSE_SQUARE, T_CLOSE_CURLY)) { 
       $i = $tokens->complementaryBracket($i); 
      } elseif ($tokens[$i]->is(T_OPEN_ROUND)) { 
       if ((($tokens[--$i]->is(T_WHITESPACE) && $tokens[--$i]->is(T_STRING)) 
        || $tokens[$i]->is(T_STRING)) 
        && !$tokens[--$i]->is(T_WHITESPACE) 
        && !$tokens[--$i]->is(T_FUNCTION) 
       ) { 
        throw new Exception('Call-time pass by reference'); 
       } 
       break; 
      } 
     } 
    } 
} 

Dies nutzt my TokenStream wrapper. Mit der nativen Ausgabe wird es ein bisschen härter;)

+0

Wenn ich negative Lookahead Assertions verwende, denke ich, dass es möglich sein könnte .Wenn niemand eine vernünftige Regexp geben kann, könnte Tokenisierung nur gewinnen :-( – Kenaniah

+1

@ircmaxell: Wenn das ''('' vorangestellt 'T_STRING' kann nicht von' T_ARRAY' vorangestellt werden;) – NikiC

+0

@Kenaniah: Das Problem ist dass Sie rekursive Klammern, Zeichenketten und Lasten anderer Sprachkonstrukte auflösen müssen. Dieses kann nicht durch Regex getan werden. – NikiC

4

php -l (php-Linter) findet Call-Time-Pass-by-Reference-Fehler, habe ich

verwendet

in Linux

+1

Dies funktioniert, wenn die PHP-Binärdatei, die Sie für die Flusenprüfung verwenden, Version 5.4 oder höher ist; Ich fand, dass ein 5,6-Liter-Check Call-Time-Pass nicht als Referenz gefunden hat. Wenn Sie die Überprüfung vor dem Upgrade von PHP auf 5.4 durchführen, müssen Sie entweder 5.4 an einem anderen Ort auf dem Server installieren oder den Check auf einem anderen Server mit 5.4 ausführen. – davejenx

0
^(?!^.*(function|foreach|array)).*\(.*\&\$.*\) 

Dies sollte helfen.

+2

Könnten Sie bitte [bearbeiten] in einer Erklärung, warum dieser Code die Frage beantwortet? Code-only-Antworten werden [entmutigt] (http://meta.stackexchange.com/q/148272/274165), weil sie die Lösung nicht lehren. –

+0

Works Wunder, danke. eine Erklärung wäre zwar abgefallen, aber nicht wirklich notwendig. – Sangoku

0

können Sie dieses Muster verwenden:

/(->|::|call_user_func|call_user_func_callable).*\(.*\&\$/ 

Es wird demnächst folgende Saiten entsprechen:

'->($arg1, &$arg2)' 
'->(&$arg1, $arg2)' 
'::($arg1, &$arg2)' 
'::(&$arg1, $arg2)' 
'call_user_func($callback, &$arg2)' 
'$callback, &$arg2)' 
'call_user_func_callable $callback, &$param_arr)' 

Bei call_user_func_callable es nicht notwendig ist, wenn der Parameter Array Referenzen hält zu überprüfen. Das Übergeben von Referenzen innerhalb eines Arrays wird nicht als Call Time Pass by Referenz betrachtet und ist völlig in Ordnung.

Verwandte Themen