Как получить тело функции из строки, содержащей функцию? - PullRequest
1 голос
/ 26 апреля 2011

Вот строка:

<?php
$string = '//ps: this placeholder text to demonstrate issues..

function go($url) {
header("Location: {$url}");
exit();
}

function some() {

/* this is the function body */

$result = mysql_query("SELECT something FROM sometable");
while ($row = mysql_fetch_assoc($result)) {

//something...
}

return "something";

/* this is the function body */

}

function fetch2($result) {

while ($row = mysql_fetch_assoc($result)) {

//something...
}

return "something";

}';
?>

Я пробовал регулярное выражение, в некоторых случаях это работает, а в других - нет (если в теле функции есть скобки, я не могу контролировать жадность).

Это то, что я пробовал:

preg_match('#function some\(\)\s*{(.+?)}#s', $string, $matches);

echo $match[1];

Однако это не дает мне полное тело функции из-за набора скобок перед закрывающей скобкой, мешающей сопоставлению.

Мой вопрос (разработан): Как я могу получить тело функции более надежно (без проблем, когда их скобки находятся перед закрывающей скобкой)?Кто-то предложил использовать token_get_all(), но я понятия не имею, как его использовать или для чего мне его использовать.

Ответы [ 3 ]

0 голосов
/ 26 апреля 2011

Вот еще одно альтернативное решение, которое читает непосредственно из файла:

$array = get_function_body('source.php', 'some');
print_r($array['body']);

function get_function_body($sourceFile, $functionName) {
    $fd = fopen($sourceFile, "r");
    while (!feof($fd)) {
        $content = fgets($fd);
        if ($content == "") { 
            continue;
        }
        if (isset($ret['args'])) {
            if ($content == "//EOF")
            break;
            if (preg_match('/^\s*function\s+/', $content)) {
                // EOFunction?
                break;
            }
            $ret['body'] .= $content;
            continue;
        }
        if (preg_match('/^\s*function\s+(.*)\s*\((.*)\)\s*\{\s*$/', $content, $resx)) {
            if ($resx[1] == $functionName) {
                $ret['args'] = $resx[2];
                $ret['body'] = "";
            }
        }
    }
    fclose($fd);
    return $ret;
}
0 голосов
/ 24 ноября 2012

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

Он не только даст вам исходный код функции PHP, на лету, но это также даст вам подробную информацию о параметрах функции (если доступно)

Так что, если функция, которую вы запрашивали, была примерно такой ...

function nearby($lat=41.1663079,$lng=-113.8584736,$distance=150)
    {
    ....
    ....
    }

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

Array(  [lat] => Array(     [position]  => 0
                [name]      => lat
                [type]      => string
                [default]   => 41.1663079
                [optional]  => 1
                [byreference]   => 0    )
    [lng] => Array(     [position]  => 1
                [name]      => lng
                [type]      => string
                [default]   => -113.8584736
                [optional]  => 1
                [byreference]   => 0    )
    [distance] => Array(    [position]  => 2
                [name]      => distance
                [type]      => string
                [default]   => 150
                [optional]  => 1
                [byreference]   => 0    )   )

Классы отражения PHP плохо документированы (часто нет документации), но было достаточно того, что с небольшим волнением сегодня, то же самое позволило создание класса PHP "func_def" ниже.

Я создал его для поддержки больших усилий, которые позволяют мне безопасно вызывать функции PHP в режиме реального времени из Javascript с проверкой типов и тому подобным.

Наслаждайтесь!

Пример:

$function_inspector =new func_def('whatever_function_name');

print "the function's source code is \n\n"
.$function_inspector->func_get_code() ;

print "the function's argument details are ".print_r($function_inspector->func_get_args());


/*
**
**  The cool func_def class
**  Scribbled up by :Dr. Clue
**
*/

class   func_def    extends ReflectionFunction
    {//http://php.net/manual/en/class.reflectionfunctionabstract.php
    protected   $sz_fun_name    =NULL   ;
    protected   $bExists    =FALSE  ;
    function    __construct($func_name)
        {
        $this->sz_func_name=$func_name;
        if(!function_exists($func_name))return;
        try         {parent::__construct($func_name);   $this->bExists=TRUE;}
        catch(Exception $e) {$this->bExists=FALSE;      return;     }
        }   //  End Functon __constructor
    function    function_valid()        {       return $this->bExists==TRUE;        }
    function    func_get_code()
        {   //  Returns Function's source code
        if(!$this->bExists){return "/* function does not exist */";}
        $line_start     =$this->getStartLine() - 1;
        $line_end       =$this->getEndLine();
        $line_count     =$line_end - $line_start;
        $line_array     =file($this->getFileName());
        return      implode("", array_slice($line_array,$line_start,$line_count));
        }   //  End Function
    function    func_get_args()
        {   //  Returns a fairly detailed descript of function arguments
        $aParamerters=Array();
        if(!$this->bExists)return $aParamerters;
        foreach($Params=$this->getParameters() as $k=>$v)
            {
            $item= Array();
            $s_export=array_pop($a=(array)$v->export($this->getName(),$v->getName(),TRUE)   );
            preg_match('/[^#]+[#]([0-9]+)/',$s_export,$m,PREG_OFFSET_CAPTURE);
            $item["position"]=$m[1][0];$item["name" ]=$v->getName();$item["default" ]=$item["type"  ]=NULL;
            if(($item["optional"]=intVal($v->isOptional()) )==1)
                if(preg_match('/[^[]+[^=]+=([^\]]+)/',$s_export,$m,PREG_OFFSET_CAPTURE))
                {$item["default"]=($ev=trim($m[1][0]));$ev=("\$a=$ev;");eval($ev);$item["type"]=gettype($ev);}
            if($item["type" ]==NULL)
                if(preg_match('/[^[]+[\[][^>]+[> ]+([^&$]+)/',$s_export,$m,PREG_OFFSET_CAPTURE))$item["type"]=($ev=trim($m[1][0]));
            $item["byreference"]=intVal(strpos($s_export,'&$')!==FALSE);
            $aParamerters[$v->getName()]=$item;
            }
        return  $aParamerters;
        }
    function    func_num_args()     {if(!$this->bExists)return FALSE;return $this->getNumberOfParameters()  ;}
    function    func_num_args_required(){if(!$this->bExists)return FALSE;return $this->getNumberOfRequiredParameters();}
    }   //  End Class
0 голосов
/ 26 апреля 2011

Вы можете попробовать что-то вроде этого

$fragments = preg_split('/([\{\}])/', $string,0,PREG_SPLIT_DELIM_CAPTURE);

$functions = array();
$currentfunctionbody = '';
$currentnesting = 0;
$functionname = '';

for($i = 0; $i<count($fragments); $i++) {

    $str = $fragments[$i];

    /* New function ? */
    preg_match("!function (.*?)\\(!", $str, $matches);
    if(count($matches) > 0) {
        $functionname = $matches[1]; }
    /* Append to function body and deal with nesting */
    else {
        if(substr($str, 0,1) == '{') { 
            $currentnesting++; }
        else if(substr($str, -1,1) == '}') { 
            $currentnesting--; }
        $currentfunctionbody.=$str;
    }

    /* Close function */
    if($currentfunctionbody != '' && $currentnesting == 0)
    {
        $functions[$functionname] = trim($currentfunctionbody,"{}");
        $currentfunctionbody = '';
        $functionname = ''; 
    }


}
print_r($functions);
...