파서
Phasis는 독립 실행형 PHP API로 자체 JavaScript 파서를 제공합니다. 소스 텍스트를 구문 분석해 형식화된 AST로 만들고, 순회한 다음 ESTree 형태의 배열 또는 JSON로 내보낼 수 있습니다. Engine를 생성하거나 코드를 실행하지 않아도 됩니다.
parseSource
public static function parseSource(string $source, string $sourceType = 'script'): Program
Phasis\Parser\Parser의 단일 호출 진입점입니다. $source를 구문 분석해 Phasis\Ast\Program 루트 노드를 반환합니다.
use Phasis\Parser\Parser;
$program = Parser::parseSource('const x = [1, 2].map(n => n * 2);');
$module = Parser::parseSource('import { x } from "./x.js"; export default x;', 'module');
$sourceType는 문법 목표를 선택합니다. 이름은 JS 파서의 같은 옵션을 따릅니다:
| 값 | 목표 |
|---|---|
script |
일반 Script. 최상위 import/export는 구문 오류이며, await는 식별자입니다 |
module |
ES Module. 암시적으로 strict 모드가 적용되며 import/export 및 최상위 await를 구문 분석합니다 |
그 밖의 값은 \InvalidArgumentException을 발생시킵니다.
직접 평가 컨텍스트에서 strict 모드를 미리 설정하거나 //# sourceURL pragma를 읽는 등 세밀한 제어가 필요하면 파서를 직접 생성하세요: new Parser($source)와 setModuleMode(), setStrictMode(), parse()를 사용합니다.
노드
모든 AST 클래스는 Phasis\Ast\Node를 확장하며 Phasis\Ast\{Declaration, Expression, Pattern, Statement} 아래에 있습니다. 노드는 변경할 수 없는 일반 값 객체입니다:
$node->type()는 노드 유형 문자열을 반환합니다. 이는 클래스의 기본 이름입니다('BinaryExpression','ArrowFunction'등).$node->location는Phasis\Lexer\SourceLocation이며line(1부터 시작),column(0부터 시작),offset(바이트 오프셋)을 포함합니다. 시작 위치만 저장되므로 노드에는 끝 오프셋이 없습니다.- 그 밖의 모든 공개 필드는 노드의 자식 및 속성입니다(
$binary->left,$binary->operator,$binary->right).
대부분의 유형 이름은 ESTree와 일치합니다. 다른 점은 다음과 같습니다:
| Phasis 유형 | ESTree 유형 |
|---|---|
ArrowFunction |
ArrowFunctionExpression |
TaggedTemplate |
TaggedTemplateExpression |
ClassMethod |
MethodDefinition |
ClassProperty |
PropertyDefinition |
AssignmentProperty |
Property (ObjectPattern 내부) |
ExportDeclaration |
ExportNamedDeclaration / ExportDefaultDeclaration / ExportAllDeclaration |
ImportSpecifier |
ImportSpecifier / ImportDefaultSpecifier / ImportNamespaceSpecifier |
일부 구조도 다릅니다. 클래스 본문의 요소 배열은 클래스 노드에 바로 들어갑니다(ClassBody 래퍼 없음). 가져오기/내보내기 이름, 문 레이블, FunctionExpression 이름은 중첩된 Identifier 노드가 아닌 문자열로 저장됩니다. 또한 super는 Identifier라는 이름의 super로 구문 분석됩니다(Super 노드 클래스는 없음). Phasis\Ast\EstreeSerializer는 이 모든 구조를 ESTree 형식으로 변환합니다.
구문 오류
잘못된 입력은 Phasis\Exceptions\SyntaxError을 발생시킵니다(대개 하위 클래스인 Phasis\Parser\ParseError). 예외 메시지 끝에 위치가 표시되며, 예외에서 구조화된 위치 정보를 확인할 수 있습니다:
use Phasis\Exceptions\SyntaxError;
use Phasis\Parser\Parser;
try {
Parser::parseSource("const a = 1;\nconst b = ;");
} catch (SyntaxError $e) {
echo $e->getMessage(); // Unexpected token (got ; ";") at line 2, column 10
echo $e->location->line; // 2
echo $e->location->column; // 10
echo $e->location->offset; // 23
}
워커
Phasis\Ast\Walker는 estraverse 방식의 진입/종료 콜백을 사용해 트리를 깊이 우선으로 순회합니다:
public static function walk(Node $node, callable $enter, ?callable $leave = null): void
두 콜백 모두 (Node $node, ?Node $parent)을 받습니다. $enter에서 Walker::SKIP을 반환하면 노드의 자식 순회를 건너뜁니다. 노드 자체의 $leave은 계속 호출됩니다.
use Phasis\Ast\Expression\Identifier;
use Phasis\Ast\Node;
use Phasis\Ast\Walker;
$names = [];
Walker::walk($program, function (Node $node) use (&$names) {
if ($node instanceof Identifier) {
$names[] = $node->name;
}
if ($node instanceof \Phasis\Ast\Expression\ArrowFunction) {
return Walker::SKIP;
}
});
순회는 읽기 전용입니다. 노드는 변경할 수 없는 값 객체이므로 교체하거나 수정할 수 없습니다.
직렬화기
Phasis\Ast\Serializer는 형식화된 AST를 배열 또는 JSON로 변환합니다. Phasis 유형 이름과 필드 배치를 사용하며 파서 내부 캐시 필드는 제거합니다:
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
이 형식은 bin/phasis --ast가 출력하는 형식입니다.
EstreeSerializer
Phasis\Ast\EstreeSerializer는 형식화된 AST를 대신 ESTree 형태의 배열로 변환합니다. 위의 차이 표에 따른 ESTree 유형 이름, ESTree 필드 이름과 순서, 합성된 ClassBody / 지정자 / source-Literal 노드, 그리고 소스에서 구문 분석한 각 노드의 start 바이트 오프셋을 포함합니다. 노드에는 시작 위치만 저장되므로 end 오프셋은 없습니다. 문자열 Literal 노드에도 raw 텍스트가 없습니다.
public static function toArray(Node $node): array
public static function toJson(Node $node, bool $pretty = false): string
public static function summarize(Node $node): string
summarize()는 노드마다 한 줄씩 결정적인 요약을 출력합니다(유형과 name= / value= / op= / kind= 속성, 깊이마다 공백 두 칸 들여쓰기). 형식은 tests/Popular/acorn의 acorn 픽스처가 만드는 AST 요약과 바이트 단위로 동일합니다. 따라서 같은 오라클이 JS 파서 경로와 이 PHP 내보내기를 모두 검증합니다:
use Phasis\Ast\EstreeSerializer;
use Phasis\Parser\Parser;
echo EstreeSerializer::summarize(Parser::parseSource('let x = a + 1;'));
// Program
// VariableDeclaration kind=let
// VariableDeclarator
// Identifier name=x
// BinaryExpression op=+
// Identifier name=a
// Literal value=1
CLI
bin/phasis --ast script.js는 파일(script 목표)을 구문 분석하고 Serializer JSON 덤프를 공백 두 칸 들여쓰기로 출력합니다. 전체 플래그 설명은 CLI를 참조하세요.