duanchi8836 2011-08-22 20:08
浏览 139
已采纳

从文件中获取类名

I have a php file which contains only one class. how can I know what class is there by knowing the filename? I know I can do something with regexp matching but is there a standard php way? (the file is already included in the page that is trying to figure out the class name).

  • 写回答

10条回答 默认 最新

  • donvo24600 2011-08-22 20:45
    关注

    There are multiple possible solutions to this problem, each with their advantages and disadvantages. Here they are, it's up to know to decide which one you want.

    Tokenizer

    This method uses the tokenizer and reads parts of the file until it finds a class definition.

    Advantages

    • Do not have to parse the file entirely
    • Fast (reads the beginning of the file only)
    • Little to no chance of false positives

    Disadvantages

    • Longest solution

    Code

    $fp = fopen($file, 'r');
    $class = $buffer = '';
    $i = 0;
    while (!$class) {
        if (feof($fp)) break;
    
        $buffer .= fread($fp, 512);
        $tokens = token_get_all($buffer);
    
        if (strpos($buffer, '{') === false) continue;
    
        for (;$i<count($tokens);$i++) {
            if ($tokens[$i][0] === T_CLASS) {
                for ($j=$i+1;$j<count($tokens);$j++) {
                    if ($tokens[$j] === '{') {
                        $class = $tokens[$i+2][1];
                    }
                }
            }
        }
    }
    

    Regular expressions

    Use regular expressions to parse the beginning of the file, until a class definition is found.

    Advantages

    • Do not have to parse the file entirely
    • Fast (reads the beginning of the file only)

    Disadvantages

    • High chances of false positives (e.g.: echo "class Foo {";)

    Code

    $fp = fopen($file, 'r');
    $class = $buffer = '';
    $i = 0;
    while (!$class) {
        if (feof($fp)) break;
    
        $buffer .= fread($fp, 512);
        if (preg_match('/class\s+(\w+)(.*)?\{/', $buffer, $matches)) {
            $class = $matches[1];
            break;
        }
    }
    

    Note: The regex can probably be improved, but no regex alone can do this perfectly.

    Get list of declared classes

    This method uses get_declared_classes() and look for the first class defined after an include.

    Advantages

    • Shortest solution
    • No chance of false positive

    Disadvantages

    • Have to load the entire file
    • Have to load the entire list of classes in memory twice
    • Have to load the class definition in memory

    Code

    $classes = get_declared_classes();
    include 'test2.php';
    $diff = array_diff(get_declared_classes(), $classes);
    $class = reset($diff);
    

    Note: You cannot simply do end() as others suggested. If the class includes another class, you will get a wrong result.


    This is the Tokenizer solution, modified to include a $namespace variable containing the class namespace, if applicable:

    $fp = fopen($file, 'r');
    $class = $namespace = $buffer = '';
    $i = 0;
    while (!$class) {
        if (feof($fp)) break;
    
        $buffer .= fread($fp, 512);
        $tokens = token_get_all($buffer);
    
        if (strpos($buffer, '{') === false) continue;
    
        for (;$i<count($tokens);$i++) {
            if ($tokens[$i][0] === T_NAMESPACE) {
                for ($j=$i+1;$j<count($tokens); $j++) {
                    if ($tokens[$j][0] === T_STRING) {
                         $namespace .= '\\'.$tokens[$j][1];
                    } else if ($tokens[$j] === '{' || $tokens[$j] === ';') {
                         break;
                    }
                }
            }
    
            if ($tokens[$i][0] === T_CLASS) {
                for ($j=$i+1;$j<count($tokens);$j++) {
                    if ($tokens[$j] === '{') {
                        $class = $tokens[$i+2][1];
                    }
                }
            }
        }
    }
    

    Say you have this class:

    namespace foo\bar {
        class hello { }
    }
    

    ...or the alternative syntax:

    namespace foo\bar;
    class hello { }
    

    You should have the following result:

    var_dump($namespace); // \foo\bar
    var_dump($class);     // hello
    

    You could also use the above to detect the namespace a file declares, regardless of it containing a class or not.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(9条)

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测