将php代码转换为字符串,与eval()相反

时间:2013-10-31 10:35:43

标签: php

如何将可调用(匿名函数)转换为eval的字符串?

我正在尝试在phpunit中编写单元测试,使用runkit来覆盖方法。特别是,runkit_method_redefine()需要一个字符串参数eval() - 稍后调用。

我希望我的测试代码有语法高亮,所以我不想在字符串中编写代码,所以我想做类似的事情

deEval(function(){ 
   return 1;
});

将输出

"return 1;"

如何轻松完成(例如,不执行源文件,查找源代码行,解析等)?

2 个答案:

答案 0 :(得分:4)

注意:我不喜欢这个解决方案,我不会向任何人推荐它,但它确实解决了问题中提出的问题。


class CallableStringifier
{
    private static $callables = array();

    public static function stringify($callable)
    {
        $id = count(self::$callables);
        self::$callables[$id] = $callable;
        return 'return ' . __CLASS__ . "::call($id, func_get_args());";
    }

    public static function call($id, $args)
    {
        return call_user_func_array(self::$callables[$id], $args);
    }
}

这适用于您的特定用例(基本上是create_function())。如果你只是eval()它将,因为它依赖于在函数上下文中。

示例:

$func = create_function('$arg1', CallableStringifier::stringify(function($arg1) {
    return $arg1;
}));

echo $func(1); // outputs 1

See it working

答案 1 :(得分:1)

写了一个效率不高的函数..(不考虑参数)

/**
 * Converts method code to string by reading source code file
 * Function brackets {} syntax needs to start and end separately from function body
 *
 * @param Callable $callable method to deevaluate
 *
 * @return string
 */
public function callableToString($callable) {
    $refFunc = new ReflectionFunction($callable);
    $startLine = $refFunc->getStartLine();
    $endLine   = $refFunc->getEndLine();

    $f      = fopen($refFunc->getFileName(), 'r');
    $lineNo = 0;

    $methodBody = '';
    while($line = fgets($f)) {
        $lineNo++;
        if($lineNo > $startLine) {
            $methodBody .= $line;
        }
        if($lineNo == $endLine - 1) {
            break;
        }
    }
    fclose($f);

    return $methodBody;
}