Pro 에디션
AST — 심층 참조
한눈에 보기
섹션 제목: “한눈에 보기”이 페이지는 Pro AST 모듈의 심층 레퍼런스입니다. 공개 빌드, 캐시, 변경, 쓰기, 방출 표면과 그 동작 계약 및 실패 모드를 다룹니다. 이 모듈은 로드된 PDF를 불변 AstDocument 트리로 파싱하고, 기록된 인메모리 변경을 적용하며, 오버레이 기반 증분 업데이트를 작성합니다. AstDocument와 AstNode는 NextPDF\Ast 네임스페이스의 Core 값 타입입니다. 이 모듈은 이들을 생산하고 소비합니다.
가용성 및 라이선싱
섹션 제목: “가용성 및 라이선싱”이 기능은 NextPDF Pro(nextpdf/pro)로 제공되며 Pro 계층 라이선스 봉투로 활성화됩니다. 해당 자격이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션 비교 및 라이선스 받기.
기능별 라이선스 플래그는 없습니다. 이것은 Pro 에디션 기능입니다. 빌드 동작은 전적으로 AstBuildOptions가 관장합니다.
공개 API 표면
섹션 제목: “공개 API 표면”| 기호 | 매개변수 | 기본 동작 | 반환 | 발생 또는 실패 예외 | 비고 |
|---|---|---|---|---|---|
AstBuilder::__construct | PdfReader $reader, AstBuildOptions $options, ?AstCache $cache = null | 로드된 리더를 빌드 옵션에 바인딩합니다. 캐싱은 선택 사항입니다 | AstBuilder | — | null 캐시는 모든 build() 호출이 재빌드함을 의미합니다. |
AstBuilder::build | string $sourceHash (PDF 바이트의 전체 SHA-256 16진수) | 캐시 조회, 암호화 거부, 구조 트리 경로, 비태그 폴백, 바운딩 박스 첨부, 캐시 저장 | AstDocument | AstUnsupportedEncryptionException, AstBuildLimitException, AstBuildTimeoutException | 캐시 적중 시 재파싱 없이 반환합니다. |
AstBuildOptions::__construct | ?int $pageRangeStart = null, ?int $pageRangeEnd = null, int $maxNodes = 100_000, int $maxDepth = 200, ?int $estimatedTokenBudget = null, int $maxMemoryBytes = 268435456, float $timeoutSeconds = 30.0, bool $useHeuristic = false | 불변 구성 값 객체 | AstBuildOptions | — | estimatedTokenBudget는 정보성 힌트이며 강제되지 않습니다. |
AstBuildOptions::pageRangeContains | int $pageIndex | 0부터 시작하는 인덱스가 구성된 범위 안에 들어가면 true | bool | — | null 경계는 열려 있으며, 둘 다 null이면 모든 페이지를 의미합니다. |
AstBuildOptions::hash | — | 모든 옵션 값에 대한 안정적인 SHA-256 | string | — | 동일한 값은 인스턴스 전반에서 동일한 해시를 산출하며, 캐시 키 세그먼트로 사용됩니다. |
AstCache::__construct | CacheInterface $backend | 임의의 PSR-16 백엔드를 래핑합니다 | AstCache | — | — |
AstCache::buildKey | string $sourceHash, AstBuildOptions $options | 키 = nextpdf_ast_v1_ + 소스 해시의 처음 32 16진수 + _ + 옵션 해시의 처음 16 16진수 | string | — | 옵션 변경은 캐시된 결과를 자동으로 무효화합니다. |
AstCache::get | string $cacheKey | 엄격한 필드별 검증을 거쳐 JSON 페이로드를 디코딩합니다 | ?AstDocument | 예외를 던지지 않으며, 실패 시 null을 반환합니다 | 잘못되거나 변조된 페이로드는 캐시 미스로 안전하게 실패합니다. |
AstCache::set | string $cacheKey, AstDocument $document | 24시간 TTL로 JSON을 저장한 뒤 즉시 재읽기로 검증합니다 | void | AstWriteVerificationException (Exception 네임스페이스) | 백엔드 쓰기 실패 또는 왕복 실패 시 예외를 발생시킵니다. |
AstCache::delete | string $cacheKey | 최선 노력(best-effort) 제거 | void | 예외를 던지지 않습니다 | 백엔드 삭제 실패는 무시됩니다. |
AstCache::has | string $cacheKey | 최선 노력 존재 확인 | bool | 예외를 던지지 않으며, 실패 시 false를 반환합니다 | — |
AstMutator::updateNode | AstDocument $document, string $nodeId, array $updates | text_content를 교체하고 Updated 항목을 기록합니다 | AstDocument (새 인스턴스) | InvalidArgumentException | text_content 키만 적용되며, 알 수 없는 키는 무시됩니다. |
AstMutator::deleteNode | AstDocument $document, string $nodeId | 인메모리 트리에서 노드를 제거하고 Deleted 항목을 기록합니다 | AstDocument (새 인스턴스) | InvalidArgumentException | 인메모리 제거만 수행합니다. 아래의 편집(redaction) 유의 사항을 참고하십시오. |
AstMutator::getMutationLog | — | 공유 로그 인스턴스를 반환합니다 | MutationLog | — | 동일한 로그를 AstWriter에 전달하십시오. |
AstMutator::resetLog | — | 기록된 모든 변경을 폐기합니다 | void | — | 새 로그를 시작합니다. |
MutationLog | record, all, isEmpty, count, forNode, mutatedNodeIds | 추가 전용 인메모리 로그, 삽입 순서 유지 | 메서드별 | — | forNode는 노드의 가장 최근 항목을 반환하며, 마지막 항목이 우선합니다. |
MutationEntry::__construct | string $nodeId, MutationType $type, ?AstNode $originalNode, ?AstNode $mutatedNode, DateTimeImmutable $timestamp | 단일 변경의 불변 레코드 | MutationEntry | — | originalNode는 Inserted에서 null이고, mutatedNode는 Deleted에서 null입니다. |
MutationType | 열거형 케이스 Updated, Inserted, Deleted | 문자열 기반 분류 | — | — | OVERLAY 하에서 Deleted는 콘텐츠를 숨길 뿐 바이트를 지우지 않습니다. |
AstWriter::write | string $originalPdfBytes, MutationLog $log | 오버레이 스트림이 변경된 바운딩 박스를 덮는 증분 업데이트를 추가합니다 | string (수정된 PDF 바이트) | AstWriteException | 빈 로그는 입력을 변경 없이 반환합니다. Inserted 항목과 바운딩 박스가 없는 항목은 건너뜁니다. |
AstWriter::writeAndVerify | string $originalPdfBytes, MutationLog $log | write()를 실행한 뒤 구조적 출력 검사를 수행합니다 | string (검증된 PDF 바이트) | AstWriteException, AstWriteVerificationException (Writer 네임스페이스) | 검증은 구조적이며 의미적이지 않습니다. |
AstPdfEmitter::emit | AstNode $root, BinaryBuffer $buffer, ObjectRegistry $registry, array $pageObjects | 제공된 트리에 대해 StructTreeRoot, StructElem 체인, ParentTree를 작성합니다 | EmitResult | AstEmitException | 루트는 자식을 가진 Document 노드여야 합니다. 구조 트리 검증을 위한 왕복(round-trip) 방출기입니다. |
EmitResult::__construct | int $structTreeRootObject, int $rootElementObject, int $parentTreeObject, int $elementObjectCount, int $parentTreeNextKey | 방출된 객체 식별자의 불변 레코드 | EmitResult | — | — |
public function build(string $sourceHash): AstDocumentpublic function updateNode(AstDocument $document, string $nodeId, array $updates): AstDocumentpublic function deleteNode(AstDocument $document, string $nodeId): AstDocumentpublic function write(string $originalPdfBytes, MutationLog $log): stringpublic function writeAndVerify(string $originalPdfBytes, MutationLog $log): string예외 계층
섹션 제목: “예외 계층”NextPDF\Pro\Ast\Exception\AstException는RuntimeException를 확장합니다 — 빌드 계층의 기반입니다.AstBuildLimitException는AstException를 확장합니다 — 노드, 깊이, 또는 메모리 상한을 초과했습니다.AstBuildTimeoutException는AstBuildLimitException를 확장합니다 — 경과 시간 빌드 타임아웃이 지났습니다.AstNoStructTreeException는AstException를 확장합니다 — 구조 트리가 없습니다.AstBuilder::build()가 내부적으로 이를 포착하고 폴백하므로,build()호출자는 이를 관찰하지 않습니다.AstUnsupportedEncryptionException는AstException를 확장합니다 — 입력 PDF가 암호화되어 있습니다.NextPDF\Pro\Ast\Exception\AstWriteVerificationException는AstException를 확장합니다 — 캐시 쓰기 검증이 실패했습니다.NextPDF\Pro\Ast\Writer\AstWriteException는RuntimeException를 확장합니다 — 작성기 입력 또는 구조 실패입니다.NextPDF\Pro\Ast\Writer\AstWriteVerificationException는AstWriteException를 확장합니다 — 쓰기 후 구조 검증이 실패했습니다.
서로 다른 네임스페이스에 두 개의 구별되는 AstWriteVerificationException 클래스가 존재합니다. AstCache::set()는 Exception 네임스페이스 클래스를 발생시키고, AstWriter::writeAndVerify()는 Writer 네임스페이스 클래스를 발생시킵니다. catch 절에서 네임스페이스를 일치시키십시오.
동작 계약
섹션 제목: “동작 계약”AstBuilder::build($sourceHash)는 소스 바이트의 전체 SHA-256 16진수를 요구합니다. 파이프라인은 다음과 같습니다. 선택적 캐시 조회, 암호화 거부, 구조 트리 경로, 비태그 폴백, 바운딩 박스 첨부, 선택적 캐시 저장입니다.
캐시 키는 소스 해시를 AstBuildOptions 해시와 결합합니다. 옵션 해시는 값이 동일한 인스턴스 전반에서 안정적이므로, 동일한 입력과 옵션은 동일한 트리를 반환합니다. 캐시가 제공되지 않으면 모든 호출이 재빌드합니다. 캐시된 페이로드는 JSON이며, 네이티브 PHP 직렬화가 아닙니다. 읽기 경로는 각 필드를 검증하고 AST 값 타입만 인스턴스화하므로, 오염된 캐시 항목은 객체 주입을 유발할 수 없고 캐시 미스로 격하됩니다.
구조 트리 경로는 구조 트리가 존재할 때 실행됩니다. 리소스 상한 — 노드 수, 깊이, 메모리 델타, 경과 시간 — 은 구조 트리 읽기 중에 강제되며 AstBuildLimitException 또는 AstBuildTimeoutException를 발생시킵니다. 리더가 구조 트리가 없다고 보고하면 빌더는 비태그 경로로 전환합니다. useHeuristic이 true이면 휴리스틱 빌더, 그렇지 않으면 기본 폴백 빌더입니다. 바운딩 박스는 범위 내 각 페이지의 콘텐츠 스트림을 분석하여 첨부됩니다. 콘텐츠 스트림을 파싱할 수 없는 페이지는 건너뛰며 트리의 나머지를 온전하게 유지합니다.
AstNode는 불변입니다. 트리 업데이트는 영향받은 노드를 상향식으로 재빌드합니다. 변경되지 않은 하위 트리는 동일성(identity)으로 반환됩니다. AstMutator는 동일한 계약을 따릅니다. 각 변경은 새 AstDocument를 반환하고, 루트에서 대상까지의 경로만 재빌드하며, 공유 MutationLog에 MutationEntry를 기록합니다.
AstWriter는 MutationLog를 OVERLAY 모드로 추가 전용 증분 업데이트로 적용합니다. 새 오버레이 콘텐츠 스트림, 업데이트된 페이지 객체, 새 객체만 포함하는 상호 참조 섹션, 그리고 /Prev가 이전 startxref를 가리키는 트레일러입니다. 원본 바이트는 ISO 32000-2:2020, 7.5.6의 증분 업데이트 모델에 따라 그대로 유지됩니다. Updated 항목에 대해 그려지는 대체 텍스트는 ISO 32000-2:2020, 7.3.4.2에 따라 리터럴 문자열에서 \, (, )를 이스케이프합니다.
AstPdfEmitter::emit()는 구조 트리 읽기의 대칭적 역연산입니다. 리더가 생성한 트리는 노드 ID 재번호 매기기와 문서화된 정규화(canonicalisation) 클래스를 제외하고 구조적으로 동등한 트리로 왕복합니다. 노드에 존재하는 MCID는 그대로 재방출되며 절대 재할당되지 않습니다.
엣지 케이스 및 실패 모드
섹션 제목: “엣지 케이스 및 실패 모드”- 암호화된 입력은 어떤 트리 작업 이전에 거부됩니다. 암호화된 PDF에 대한 부분 트리 결과는 없습니다. 먼저 복호화하십시오.
- 리소스 상한: 최대 노드(기본 100,000), 최대 깊이(기본 200), 최대 메모리(기본 256 MiB), 경과 시간 타임아웃(기본 30 s). 상한을 초과하면
AstBuildLimitException를 발생시키고, 타임아웃은 그 하위 클래스인AstBuildTimeoutException를 발생시킵니다. - 페이지 범위는 0부터 시작하며 양 끝을 포함합니다. null 경계는 모든 페이지를 의미합니다.
- 콘텐츠 스트림을 파싱할 수 없는 페이지는 바운딩 박스 첨부 중에 건너뜁니다. 트리의 나머지는 영향을 받지 않습니다.
AstCache::get()는 예외를 던지지 않습니다. 잘못되었거나, 변조되었거나, 문자열이 아닌 페이로드는 null을 반환하고 재빌드를 강제합니다.AstCache::set()는 백엔드 쓰기 또는 즉시 재읽기가 실패하면 명시적으로 실패합니다.AstMutator는 노드 ID를 찾을 수 없을 때InvalidArgumentException를 발생시킵니다. 알 수 없는 업데이트 키는 조용히 무시되며,text_content만 적용됩니다.AstWriter::write()는 입력에%PDF-헤더 또는 찾을 수 있는startxref가 없을 때AstWriteException를 발생시킵니다. 바운딩 박스가 없는 항목은 조용히 건너뜁니다. 객체 스캔으로 위치를 찾을 수 없는 페이지 — 예를 들어 압축된 상호 참조 스트림 하에서 — 는 건너뜁니다. 적용할 수 있는 오버레이가 없으면 입력 바이트를 변경 없이 반환합니다.- OVERLAY 출력은 편집(redaction)이 아닙니다. 흰색 사각형과 다시 그려진 텍스트가 추가될 뿐, 원본 콘텐츠 바이트는 파일에 남아 있으며 원시 추출로 복구할 수 있습니다. GDPR Art. 17 삭제나 법적 편집(redaction)에 사용하지 마십시오. 재구성(reconstruct) 모드 작성기가 소스 트리에 존재하지만 내부용으로 표시되어 있고, 프로덕션 준비가 되지 않았으며, 지원되는 API 표면 밖에 있습니다.
- 작성기가 페이지 MediaBox를 읽지 않으므로 오버레이 기하는 A4 세로(595 x 842 pt)를 가정합니다. A4가 아닌 페이지에서는 오버레이가 약간 어긋날 수 있습니다. 출력은 구조적으로 유효한 상태를 유지합니다.
writeAndVerify()는 구조만 검사합니다. 헤더, 후행%%EOF, 출력 증가입니다. 변경된 문서를 의미적으로 재파싱하지는 않습니다.AstPdfEmitter::emit()는 루트가 Document 노드가 아니거나 자식이 없을 때AstEmitException를 발생시킵니다. OBJR(주석) 동반 항목은 이번 릴리스에서 방출되지 않습니다.- 이 모듈은 암호화 작업을 수행하지 않으며 FIPS 관련 동작을 정의하지 않습니다. SHA-256은 캐시 키의 콘텐츠 주소 지정으로만 등장합니다.
적합성
섹션 제목: “적합성”구조 트리 경로는 ISO 32000-2가 정의하는 태그된 PDF 논리 구조 기능을 읽습니다. 작성 시점에 사용 가능한 RAG 코퍼스에는 논리 구조 조항이 포함되어 있지 않으므로, 그 진술은 소스 주석에서 제품 기반으로 확인됩니다. 작성기의 증분 업데이트 레이아웃은 ISO 32000-2:2020, 7.5.6(아래 인용)을 따르며, 리터럴 문자열 이스케이프는 ISO 32000-2:2020, 7.3.4.2(아래 인용)을 따릅니다.
이 진술들은 인용된 조항에 대한 능력을 설명합니다. NextPDF는 어떤 적합성 인증도 보유하고 있지 않으며, 조항에 대한 지원이 인증 주장은 아닙니다.
개발 노트
섹션 제목: “개발 노트”- 로드된
PdfReader마다 하나의AstBuilder를 구성하십시오. 파싱 비용을 분산하려면 빌드 전반에서AstCache를 재사용하십시오. 키 설계 덕분에 옵션 변경이 자체적으로 무효화됩니다. - 작성기가 기록된 세션을 정확히 적용하도록
AstMutator와AstWriter사이에서 하나의MutationLog를 공유하십시오. 독립적인 편집 세션 사이에는resetLog()를 호출하십시오. - 레이아웃 기반 그룹화가 기본 폴백 트리보다 선호될 때, 비태그 문서에 대해
useHeuristic를 true로 설정하십시오. - 빌드는 동일한 바이트와 옵션에 대해 결정론적입니다. 스냅샷 스타일 테스트에서 이를 신뢰하십시오.
- 빌드 실패는
NextPDF\Pro\Ast\Exception계층을 통해, 쓰기 실패는NextPDF\Pro\Ast\Writer계층을 통해 포착하십시오. 둘은RuntimeException아래에서 기반을 공유하지 않습니다.
게시 경계
섹션 제목: “게시 경계”이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일 이름, 티켓 접두사는 범위 밖입니다.