2010-11-22 6 views
2

In einem System, das wir verwenden werden, gibt es eine Funktion namens "verwendet". Wenn Sie mit pascal vertraut sind, gibt die uses-Klausel Ihrem Programm an, welche Abhängigkeiten es hat (ähnlich wie C und PHP). Diese Funktion wird verwendet, um die Dateieinfügung mit Ausnahme von include (_once) oder require (_once) weiter zu steuern.PHP Konstante Zeichenfolge Parameter Token

Als Teil der Testverfahren muss ich ein Abhängigkeits-Visualisierungstool für statisch geladene Dateien schreiben.

Statisch Loaded Beispiel: uses('core/core.php','core/security.php');

dynamisch nachgeladen Beispiel: uses('exts/database.'.$driver.'.php');

Ich brauche dynamische Lastfälle, um herauszufiltern, da der Code statisch getestet wird, nicht während des Betriebs.

Dies ist der Code, den ich zu diesem Zeitpunkt bin mit:

$inuses=false; // whether currently in uses function or not 
$uses=array(); // holds dependencies (line=>file) 
$tknbuf=array(); // last token 
foreach(token_get_all(file_get_contents($file)) as $token){ 
    // detect uses function 
    if(!$inuses && is_array($token) && $token[0]==T_STRING && $token[1]=='uses')$inuses=true; 
    // detect uses argument (dependency file) 
    if($inuses && is_array($token) && $token[0]==T_CONSTANT_ENCAPSED_STRING)$tknbuf=$token; 
    // detect the end of uses function 
    if($inuses && is_string($token) && $token==')'){ 
     $inuses=false; 
     isset($uses[$tknbuf[2]]) 
      ? $uses[$tknbuf[2]][]=$tknbuf[1] 
      : $uses[$tknbuf[2]]=array($tknbuf[1]); 
    } 
    // a new argument (dependency) is found 
    if($inuses && is_string($token) && $token==',') 
     isset($uses[$tknbuf[2]]) 
      ? $uses[$tknbuf[2]][]=$tknbuf[1] 
      : $uses[$tknbuf[2]]=array($tknbuf[1]); 
} 

Hinweis: Es kann helfen, zu wissen, dass ich einen Zustand Motor bin mit den Argumenten zu erkennen.

Mein Problem? Da es alle möglichen Argumente gibt, die in der Funktion vorkommen können, ist es sehr schwierig, es richtig zu machen. Vielleicht verwende ich nicht den richtigen Ansatz, aber ich bin mir ziemlich sicher, token_get_all ist in diesem Fall das beste. Vielleicht ist das Problem meine State Engine, die wirklich nicht so gut ist. Ich könnte den einfachen Ausweg vermissen, dachte, ich würde ein paar Peer Review davon bekommen.

Bearbeiten: Ich nahm den Ansatz zu erklären, was ich diesmal mache, aber nicht genau das, was ich will. In einfachen Worten, ich muss ein Array der Argumente erhalten, die an eine Funktion namens "verwendet" übergeben werden. Die Sache ist, ich bin ein bisschen spezifisch in Bezug auf die Argumente; Ich brauche nur eine Reihe von geraden Strings, keinen dynamischen Code (Konstanten, Variablen, Funktionsaufrufe ...).

+1

Darf ich fragen, warum nicht einfach Autoloading von Klassen verwenden? – Mchl

+0

Wirklich, vergiss die Regex = böses Meme. Das ** ist ** ein Anwendungsfall für sie. – mario

+0

@Mchl - Weil dies nicht speziell Klassen betrifft. @ Mario - Zugegeben, ich bin nicht so gut mit Regexes. In jedem Fall, ich Regex PHP-Code zu analysieren wäre schwer zu erstellen und zu pflegen sowie ziemlich langsam zu laufen. – Christian

Antwort

1

OK Ich habe es funktioniert. Nur ein paar kleinere Korrekturen an der State Engine. Kurz gesagt, Argument-Token werden gepuffert und nicht direkt in das uses-Array eingefügt. Als nächstes überprüfe ich bei jedem ',' oder ')', ob das Token gültig ist oder nicht und füge es dem uses-Array hinzu.

$inuses=false; // whether currently in uses function or not 
$uses=array(); // holds dependencies (line=>file) 
$tknbuf=array(); // last token 
$tknbad=false; // whether last token is good or not 
foreach(token_get_all(file_get_contents($file)) as $token){ 
    // detect uses function 
    if(!$inuses && is_array($token) && $token[0]==T_STRING && $token[1]=='uses')$inuses=true; 
    // token found, put it in buffer 
    if($inuses && is_array($token) && $token[0]==T_CONSTANT_ENCAPSED_STRING)$tknbuf=$token; 
    // end-of-function found check buffer and throw into $uses 
    if($inuses && is_string($token) && $token==')'){ 
     $inuses=false; 
     if(count($tknbuf)==3 && !$tknbad)isset($GLOBALS['uses'][$file][$tknbuf[2]]) 
       ? $GLOBALS['uses'][$file][$tknbuf[2]][]=$tknbuf[1] 
       : $GLOBALS['uses'][$file][$tknbuf[2]]=array($tknbuf[1]); 
     $tknbuf=array(); $tknbad=false; 
    } 
    // end-of-argument check token and add to $uses 
    if($inuses && is_string($token) && $token==','){ 
     if(count($tknbuf)==3 && !$tknbad)isset($GLOBALS['uses'][$file][$tknbuf[2]]) 
      ? $GLOBALS['uses'][$file][$tknbuf[2]][]=$tknbuf[1] 
      : $GLOBALS['uses'][$file][$tknbuf[2]]=array($tknbuf[1]); 
     $tknbuf=array(); $tknbad=false; 
    } 
    // if current token is not an a simple string, flag all tokens as bad 
    if($inuses && is_array($token) && $token[0]!=T_CONSTANT_ENCAPSED_STRING)$tknbad=true; 
} 

Edit: Eigentlich ist es immer noch fehlerhaft (ein anderes Problem, obwohl). Aber die neue Idee, die ich hatte, sollte gut funktionieren.

+0

Einmal in einer 'uses' Funktion, würde ich wiederholen: a) Lese-Token, b) wenn Token == '(', eins zum Zähler hinzufügen. C) wenn counter> 0: if ')', dann counter else verringern ignorieren. d) wenn counter == 0: wenn ')' getan. wenn ',' neu beginnen; sonst fügen Sie ein Token zur Liste hinzu. Wenn die aktuelle Liste (nach Schritt d) nichts anderes als eine einzelne konstante Zeichenfolge ist, können Sie sie zu den Abhängigkeiten hinzufügen. Nochmal, nicht narrensicher, aber wahrscheinlich gut genug. – Matthew

1

Verwenden von regulären Ausdrücken:

<?php 
preg_match_all('/uses\s*\((.+)\s*\)/', 
    file_get_contents('uses.php'), $matches, PREG_SET_ORDER); 

foreach ($matches as $set) { 
    list($full, $match) = $set; 

    echo "$full\n"; 

    // try to remove function arguments 
    $new = $match; 
    do { 
    $match = $new; 
    $new = preg_replace('/\([^()]*\)/', '', $match); 
    } while ($new != $match); 

    // iterate over each of the uses() args 
    foreach (explode(',', $match) as $arg) { 
    $arg = trim($arg); 
    if (($arg[0] == "'" || $arg[0] == '"') && substr($arg,-1) == $arg[0]) 
    echo " ".substr($arg,1,-1)."\n"; 
    } 
} 
?> 

Rennen gegen:

uses('bar.php', 'test.php', $foo->bar()); 
uses(bar('test.php'), 'file.php'); 
uses(bar(foo('a','b','c')), zed()); 

Ausbeuten:

uses('bar.php', 'test.php', $foo->bar()) 
    bar.php 
    test.php 
uses(bar('test.php'), 'file.php') 
    file.php 
uses(bar(foo('a','b','c')), zed()) 

Offensichtlich hat es Einschränkungen und Annahmen, aber wenn Sie wissen, wie der Code aufgerufen wird , könnte es ausreichen.