我有一个包含一些类的文件夹,另一个包含一些函数。
通常每个文件有一个类或函数,但情况并非总是如此。
在某些情况下,一个类可能会附带一个或两个函数,并且某些函数可能会组合在一起。
我正在阅读每个文件,并根据每个文件的详细评论构建一个好的手册。
我认为抓住类或函数的代码会很好。
但我还没有找到办法。
正则表达式是不可能的,因为它们只能匹配简单的函数。
我找到了PHP Tokenizer,但我无法弄清楚它是如何帮助的。
谷歌也没有帮助。我正在寻找一个纯PHP解决方案(如果存在)。
假设我有这样的代码:
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
function monkey() {
return new BaseClass();
}
function weasel() {
return new SubClass();
}
function dragon() {
return new OtherSubClass();
}
我想解析它并得到一个包含6个条目的数组,每个类一个,每个函数一个。
答案 0 :(得分:1)
您所需要的基本上是一个解析器,以便您可以选择感兴趣的结构。然后,您可以使用位置信息,例如解析器收集(如果设计得很好),确定文件中文本的边界以提取该结构,或者“解压缩”已解析结构的AST以获取工件。
NikiC在此SO question中描述了他在PHP中搜索和最终构建一个这样的解析器。那里提供了其他解决方案,包括我的,但它不在PHP中。
您可能在选择所需的确切功能时遇到一些麻烦。想象一下,你有一个带有两个类C1和C2的文件,每个类都包含一个名为M.的方法。现在要选择“正确的方法”,你需要有完整的路径C1 :: M可用,你需要检查方法M在正确的C1类中找到。您可以通过从M向上走分析树来执行此操作。如果您有特征,这可能会变得更难,因为方法M可能在特征中定义,然后集成到类定义中。要做到这一点真的,你需要PHP的名称解析。
如果你走得那么远,你可能需要滥用Hip Hop(PHP-to-C编译器)来提取你想要的东西,假设它可能以可用的形式构建AST和完整的符号表。 (我不知道它是否确实如此)。
答案 1 :(得分:0)
<?php
/**moDO(Classes)(Parsers)(parse_php)
@(Description)
Parses php code and generates an array with the code of the classes and stand-alone functions found.
@(Description){note warn}
Curly brackets outside the code structures can break the parser!
@(Syntax){quote}
object `parse_php` ( string ~$path~ )
@(Parameters)
@(Parameters)($path)
Path to the php file to be parsed.
@(Return)
Returns an object that contains a variable `parsed` that contains the resulting array.
@(Examples)
@(Examples)(1){info}
`Example 1:` Basic usage example.
@(Examples)(2){code php}
$parser = new parse_php(__FILE__);
print_r($parser->parsed);
@(Changelog){list}
(1.0) ~Initial release.~
*/
/**
* Parses php code and generates an array with the code of the classes and stand-alone functions found.
* Note: Curly brackets outside the code structures can break the parser!
* @syntax new parse_php($path);
* @path string containing path to file to be parsed
*/
class parse_php {
public $parsed = false;
/**
* Validates the path parameter and starts the parsing.
* Once parsing done it sets the result in the $parsed variable.
* @path string representing valid absolute or relative path to a file.
*/
function __construct($path) {
if(is_file($path)) {
$this->parsed = $this->load($path);
}
}
/**
* This loads prepares the contents for parsing.
* It normalizes the line endings, builds lines array and looks up the structures.
* @path string representing valid absolute or relative path to a file.
*/
private function load($path) {
$file = file_get_contents($path);
$string = str_replace(Array("\r\n", "\r", "\n"), Array("\n", "\n", "\r\n"), $file);
$array = explode("\r\n", $string);
preg_match_all('/((abstract[ ])?(function|class|interface)[ ]+'
.'[a-z_\x7f-\xff][a-z0-9_\x7f-\xff]+[ ]*(\((.+)?\)[ ]*)?)'
.'([ ]*(extends|implements)[ ]*[a-z_\x7f-\xff]'
.'[a-z0-9_\x7f-\xff]+[ ]?)?[ ]*(\r|\n|\r\n)*[ ]*(\{)/i'
, $string
, $matches);
$filtered = Array();
foreach($matches[0] AS $match) {
list($first, $rest) = explode("\r\n", $match, 2);
$filtered[] = $first;
}
return $this->parse($array, $filtered);
}
/**
* The parser that loops the content lines and builds the result array.
* It accounts for nesting and skipps all functions that belong to a class.
* @lines array with the lines of the code file.
* @matches array containing the classes and possible stand-alone functions to be looked up.
*/
private function parse($lines, $matches) {
$key = false;
$track = false;
$nesting = 0;
$structures = Array();
foreach($lines AS $line) {
if($key === false)
$key = $this->array_value_in_string($line, $matches);
if($key !== false) {
if($nesting > 0)
$track = true;
$nesting = $nesting + substr_count($line, ' {');
$nesting = $nesting - substr_count($line, ' }');
$structures[$key][] = $line;
if($track && $nesting == 0) {
$track = false;
$key = false;
}
}
}
return array_values($structures);
}
/**
* Checks if any of the (array)needles are found in the (string)haystack.
* @syntax $this->array_value_in_string($string, $array);
* @haystack string containing the haystack subject of the search.
* @needles array containing the needles to be searched for.
*/
private function array_value_in_string($haystack, $needles) {
foreach($needles AS $key => $value) {
if(stristr($haystack, $value))
return $key;
}
return false;
}
}
/**
* Example execute self
*/
header('Content-type: text/plain');
$parser = new parse_php('test.php');
print_r($parser->parsed);