如何从包含函数的字符串中获取函数体?

时间:2011-04-26 13:50:37

标签: php tokenize

下面是字符串:

<?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];

然而,由于在右大括号干扰匹配之前的一组大括号,这并没有给我完整的函数体。

我的问题(el):我怎样才能更可靠地获得功能体(当它们在闭合支架前支撑时没有麻烦)?有人建议使用token_get_all(),但我不知道如何使用它或我应该使用它。

3 个答案:

答案 0 :(得分:0)

您可以尝试这样的事情

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

答案 1 :(得分:0)

这是另一种直接从文件中读取的替代解决方案:

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

答案 2 :(得分:0)

今天刚刚发生需要一个工具来检查源代码 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函数。

享受!

实施例

$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