PHP AST란
AST(Abstract Syntax Tree / 추상 구문 트리)는 소스 코드를 “의미 있는 구조”로 분해한 트리 구조입니다. 여러분이 코드 생성 도구, 정적 해석 도구, 자동 리팩터링 도구를 만들 때, AST는 거의 필수의 기반이 됩니다. 문자열 치환으로는 부서지기 쉬운 변환이라도, AST를 사용하면 “function call”, “class declaration”, “use statement”와 같은 구문 단위로 안전하게 다룰 수 있습니다.
PHP의 내부 AST
PHP 7 이후의 Zend Engine은, PHP 코드를 곧바로 opcode로 변환하는 것이 아니라, 먼저 내부 AST로 변환한 뒤 컴파일합니다.php -r로 실행하는 1줄 코드라도, 내부적으로는 같은 컴파일 파이프라인을 거칩니다- OPcache는 최종적으로 생성된 opcode를 캐시하여 재이용합니다
- 일반적인 앱 개발에서는, 이 내부 AST를 직접 조작할 기회는 거의 없습니다
nikic/PHP-Parser 패키지
nikic/PHP-Parser는, PHP 코드를 AST로서 해석·순회·재생성하기 위한 표준적인 라이브러리입니다. README와 공식 문서에서는, 다음 3단계가 기본으로서 설명되고 있습니다.설치
기본적인 파스 예(코드를 AST로 변환)
NodeVisitor 패턴으로 AST를 순회·변경
NodeVisitorAbstract를 상속하면, 필요한 훅(enterNode / leaveNode)만 구현할 수 있습니다. 복잡한 변환에서는, enterNode에서 정보를 모아 leaveNode에서 치환하는 흐름이 유효합니다.
Pretty Printer로 코드를 재생성
Laravel/Chisel에서의 사용 예
laravel/chisel은, 스타터 킷을 후처리로 깎아내기 위한 라이브러리입니다.composer.json에서는 nikic/php-parser의 5.x 계열을 의존 관계에 포함하고 있습니다.
Chisel의 Laravel\Chisel\Ast\Source에서는, 다음의 절차로 AST 편집을 실행하고 있습니다.
ParserFactory::createForNewestSupportedVersion()으로 코드를 파스NodeTraverser에 여러 Visitor(RemoveImportVisitor등)를 추가하여 변환PhpParser\PrettyPrinter\Standard의printFormatPreserving()으로 원래의 포맷을 유지하면서 되돌려 씀
use 문·trait·interface의 삭제를 텍스트 치환이 아닌 구문 기반으로 안전하게 실행할 수 있습니다.
유스케이스
AST를 사용하면 다음과 같은 개발을 진행하기 쉬워집니다.- 코드 생성 CLI(뼈대 생성 후 구문 단위로 편집)
- 정적 해석 도구(특정 구문의 검출, 룰 위반의 검출)
- 자동 리팩터링(API 이관이나 명명 변경의 반자동화)
- 프로젝트 템플릿의 후처리(Chisel과 같은 기능 삭제·치환)
정리
PHP AST는, 일반적인 Laravel 앱 개발에서는 매일 사용하는 기능은 아닙니다. 다만, 여러분이 도구 개발이나 패키지 개발을 진행한다면, AST는 “부서지기 어렵고 재현성 있는 코드 변경”을 실현하는 강력한 기반이 됩니다. 우선은nikic/php-parser의 Parser·Visitor·Pretty Printer의 3가지를 작은 CLI로 시험해 보세요.