【问题标题】:Get functions and classes defined in file?获取文件中定义的函数和类?
【发布时间】:2011-10-03 22:20:06
【问题描述】:

我正在遍历目录中的所有文件。现在我想获取它们中定义的所有函数和类。从那里,我可以使用ReflectionClass 进一步检查它们。我不知道如何获取文件中定义的所有函数和类。

ReflectionExtension 看起来最接近我想要的,除了我的文件不是扩展的一部分。是否有一些我忽略的类或函数?

【问题讨论】:

  • 您是让 php 通过 include/require 解析文件还是尝试自己解析文本?
  • 反射需要将文件加载到脚本中。听起来您想要一个更像PHP_Token_Stream 的工具。
  • @salathe:PHP_Token_Stream 的文档是否比首页上的更多?并没有真正告诉我它的作用。
  • @webbiedave:不太清楚你想问什么。我根本不包括/需要这些文件。而且我并不完全想“自己解析文本”——我想让反射类为我做这件事,因为自己解析它会有点疯狂:D

标签: php reflection


【解决方案1】:

很好的问题。 get_declared_classesget_defined_functions 可能是一个很好的起点。在尝试确定给定文件中的内容时,您必须注意已经定义了哪些类/函数。

此外,不确定您的最终目标是什么,但 PHP DependPHP Mess Detector 等工具可能会执行与您想要的类似的操作。我建议您也检查一下。

【讨论】:

  • get_declared_classes 正是这样做的……只得到声明的那些。这意味着我必须首先包含每个文件。问题在于这些文件中的许多都意味着以特定方式包含(不是独立的/需要首先包含其他文件)。另外,我不想运行这些文件(其中一些在函数/类之外有很少的脚本)。
  • @Mark 如果你想使用反射,你必须加载类。也许查看链接到的 PHP_Token_Steam 工具,或者尝试使用 php.net/token_get_all 将一些东西放在一起。
  • 哦...我猜你是对的。我必须包括他们。真可惜。我还是不知道PHP_Token_Stream这个工具是干什么的。
【解决方案2】:

这是我能想到的最好的(courtesy):

function trimds($s) {
    return rtrim($s,DIRECTORY_SEPARATOR);
}

function joinpaths() {
    return implode(DIRECTORY_SEPARATOR, array_map('trimds', func_get_args()));
}

$project_dir = '/path/to/project/';

$ds = array($project_dir);

$classes = array();

while(!empty($ds)) {
    $dir = array_pop($ds);
    if(($dh=opendir($dir))!==false) {
        while(($file=readdir($dh))!==false) {
            if($file[0]==='.') continue;
            $path = joinpaths($dir,$file);
            if(is_dir($path)) {
                $ds[] = $path;
            } else {
                $contents = file_get_contents($path);
                $tokens = token_get_all($contents);
                for($i=0; $i<count($tokens); ++$i) {
                    if(is_array($tokens[$i]) && $tokens[$i][0] === T_CLASS) {
                        $i += 2;
                        $classes[] = $tokens[$i][1];
                    }
                }
            }
        }
    } else {
        echo "ERROR: Could not open directory '$dir'\n";
    }
}

print_r($classes);

希望我不必像这样解析文件并遍历所有标记。


忘记了以前的解决方案使我无法根据需要使用反射。新解决方案:

$project_dir = '/path/to/project/';

$ds = array($project_dir);

while(!empty($ds)) {
    $dir = array_pop($ds);
    if(($dh=opendir($dir))!==false) {
        while(($file=readdir($dh))!==false) {
            if($file[0]==='.') continue;
            $path = joinpaths($dir,$file);
            if(is_dir($path)) {
                $ds[] = $path;
            } else {
                try{
                    include_once $path;
                }catch(Exception $e) {
                    echo 'EXCEPTION: '.$e->getMessage().PHP_EOL;
                }
            }
        }
    } else {
        echo "ERROR: Could not open directory '$dir'\n";
    }
}

foreach(get_declared_classes() as $c) {
    $class = new ReflectionClass($c);
    $methods = $class->getMethods();
    foreach($methods as $m) {
        $dc = $m->getDocComment();
        if($dc !== false) {
            echo $class->getName().'::'.$m->getName().PHP_EOL;
            echo $dc.PHP_EOL;
        }
    }
}

【讨论】:

  • 很遗憾,这不会涵盖命名空间类。
  • @richremer 你确定? ReflectionClass 中应该有一些东西给你完全限定的名字,不是吗?
  • 我在看第一个块,它不使用 ReflectionClass。第二个块将使用命名空间,但它似乎可以识别所有类,而不仅仅是特定文件中定义的类。
  • 我认为第一个解决方案更接近,它只需要查找 T_NAMESPACE 令牌以及 T_CLASS 令牌,并跟踪解析器遇到类时将在哪个命名空间中。不过,我认为它仍然存在命名空间别名的潜在问题。
  • @richremer 是的......第一个解决方案绝对是可取的。如果您修复它,请将其作为答案发布:-)
猜你喜欢
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 2020-05-22
  • 1970-01-01
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多