php_parser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php

$code = <<<'CODE'
<?php

function test($foo)
{
var_dump($foo);
}

class Cat
{
public int $a = 1;
protected float $b = 2;
public function __construct($a) {
$this->a = $a;
}
}
$cat = new Cat(1);
$f = function () use ($cat){
echo $cat;
};
CODE;

/**
* 创建一个php7的语法解析器(Parser),在没有传入词法解析器(Lexer)的时候会创建一个默认的词法分析器
* 同时如果没有指定只使用php7的语法解析器,那么将会同时创建一个php7和一个php5的parser
*/
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);

try {
/* @var $parser Multiple */
$ast = $parser->parse($code);
/**
* 解析时先使用[0]解析器,当解析存在报错时,会调用后续的解析器,直至等到一个完全没有解析错误的结果
*
* 上面的都不重要
*
*/
} catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n";
return 1;
}

$dumper = new NodeDumper;
echo $dumper->dump($ast) . "\n";
1
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);

创建一个php7的语法解析器(Parser),在没有传入词法解析器(Lexer)的时候会创建一个默认的词法分析器
同时如果没有指定只使用php7的语法解析器,那么将会同时创建一个php7和一个php5的parser

默认lexer

1
2
3
4
public function create(int $kind, Lexer $lexer = null, array $parserOptions = []) : Parser {
if (null === $lexer) {
$lexer = new Lexer\Emulative();
}
默认parser
1
2
3
4
case self::PREFER_PHP7:
return new Parser\Multiple([
new Parser\Php7($lexer, $parserOptions), new Parser\Php5($lexer, $parserOptions)
]);

解析时先使用[0]解析器,当解析存在报错时,会调用后续的解析器,直至等到一个完全没有解析错误的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public function parse(string $code, ErrorHandler $errorHandler = null) {
if (null === $errorHandler) {
$errorHandler = new ErrorHandler\Throwing;
}

list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code);
if ($firstError === null) {
return $firstStmts;
}

for ($i = 1, $c = count($this->parsers); $i < $c; ++$i) {
list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code);
if ($error === null) {
return $stmts;
}
}

throw $firstError;
}

上述都不重要

自己传入异常,当有错的时候抛出这个写法有点意思呀

这个项目用的是get_token_all研究卒