2010-11-22 2 views
2

В системе, которую мы будем использовать, есть функция, называемая «uses». Если вы знакомы с pascal, предложение uses - это то, где вы сообщаете своей программе, какие зависимости у него есть (аналогично C и PHP). Эта функция используется для дальнейшего управления включением файлов, кроме include (_once) или require (_once).PHP Постоянный токен параметров строки

Как часть процедур тестирования, мне нужно написать средство визуализации зависимостей для статически загружаемых файлов.

нагруженный Пример Статический: uses('core/core.php','core/security.php');

динамически нагруженный Пример: uses('exts/database.'.$driver.'.php');

мне нужно отфильтровать динамические нагрузки случаев, так как код проверяется статический, а не во время работы.

Это код, я использую в настоящее время:

$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]); 
} 

Примечание: Это может помочь узнать, что я использую состояние двигателя для обнаружения аргументов.

Моя проблема? Поскольку в функции есть всевозможные аргументы, это очень сложно сделать правильно. Возможно, я не использую правильный подход, однако, я уверен, что использование token_get_all является лучшим в этом случае. Так что, может быть, проблема в том, что мой механизм состояния действительно не так хорош. Возможно, мне не хватало простого выхода, подумал, что я получу отзыв о нем.

Редактировать: Я принял подход, объяснив, что я делаю на этот раз, но не совсем то, что я хочу. Проще говоря, мне нужно получить массив аргументов, передаваемых функции с именем «uses». Дело в том, что я немного разбираюсь в аргументах; Мне нужен только массив прямых строк, никакого динамического кода вообще (константы, переменные, вызовы функций ...).

+1

Могу я спросить, почему бы просто не использовать автозагрузку классов? – Mchl

+0

Действительно, забудьте о регулярном выражении = evil mem. Это ** является прецедентом для них. – mario

+0

@Mchl - Потому что это не относится конкретно к классам. @Mario - По общему признанию, я не так хорош с регулярными выражениями. В любом случае, я regex для синтаксического анализа PHP-кода было бы сложно создать и поддерживать, а также довольно медленно запускать. – Christian

ответ

1

OK Я получил его работу. Просто некоторые незначительные исправления для механизма состояния. Короче говоря, токены аргументов буферизуются, а не помещаются в массив uses напрямую. Далее, на каждом «,» или «)« Я проверяю, является ли токен действительным или нет, и добавьте его в массив uses.

$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; 
} 

Редактировать: На самом деле все еще неисправен (другой вопрос). Но новая идея, которую я должен был хорошо проработать.

+0

Однажды в функции 'uses' я бы повторил: a) прочитал токен, b) если токен == '(', добавьте один к счетчику. C), если counter> 0: if ')', а затем уменьшите счетчик else игнорировать. d) если счетчик == 0: if ')' сделан. если «,» начинаются; else добавить токен в список. Если текущий список (после шага d) является ничем иным, как единственной константной строкой, вы можете добавить его в зависимости. Опять же, не дурацкое доказательство, но, вероятно, достаточно хорошее. – Matthew

1

Использование регулярных выражений:

<?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"; 
    } 
} 
?> 

Бег против:

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

Урожайность:

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()) 

Очевидно, что имеет ограничения и предположения, но если вы знаете, как называется кодом , этого может быть достаточно.

Смежные вопросы