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

发布于 2024-11-03 13:20:30 字数 869 浏览 2 评论 0原文

这是字符串:

<?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() 但我不知道如何使用它或者我应该用它做什么。

Heres the string:

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

}';
?>

I've tried regex it works on some occasions and other occasions it doesn't (if there are braces within the function body I can't control the greedyness).

This is what I tried:

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

echo $match[1];

However, this does not give me the complete function body due to the set of braces before the closing brace interfering with the matching.

My question (ellaborated): How can I get the function body more reliably (without it being troublesome when theirs braces before the closing brace)? Someone suggested to use token_get_all() but I have no clue how to use it or what I should use it for.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

森末i 2024-11-10 13:20:30

你可以尝试这样的事情

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

You can try something like this

$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);
嘦怹 2024-11-10 13:20:30

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

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

Here is another alternative solution that reads directly from a file:

$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;
}
饮惑 2024-11-10 13:20:30

今天正好需要一个工具来检查源码
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”类。

我构建它是为了支持更大的工作,让我可以通过类型检查等从 Javascript 安全地实时调用 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

Just happened today to have a need for a tool to examine the source code of
PHP functions on-the-fly, and not really seeing anything interesting around ,
I tossed together the class pasted down below that uses some of PHP's reflection classes.

It will not only give you the source code of the PHP function , on-the-fly,
but it will also give you detailed information on the function's parameters (when available)

So if the function you were interrogating was something like this....

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

... The class would aside from the function's source , give you detailed
field information like this...

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's reflection classes are not well documented ,(often no documentation),
but there was enough that with a little fidgeting today, same allowed the creation
of the PHP "func_def" class below.

I built it to support a larger effort that lets me securely call PHP functions in real time from Javascript with type checking and such.

Enjoy!

EXAMPLE:

$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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文