Pro редакция
AST — глубокий справочник
Краткий обзор
Заголовок раздела «Краткий обзор»Эта страница — глубокий справочник по модулю Pro AST. Она охватывает публичные поверхности построения, кэширования, мутации, записи и эмиссии, их контракты поведения и режимы сбоев. Модуль разбирает загруженный PDF в неизменяемое дерево AstDocument, применяет журналируемые мутации в памяти и записывает инкрементные обновления на основе наложений. AstDocument и AstNode — типы-значения Core в пространстве имён NextPDF\Ast; этот модуль их производит и потребляет.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы этой возможности. Сравнить редакции и получить лицензию.
Пофункционального лицензионного флага нет. Это возможность редакции Pro. Поведение построения полностью определяется AstBuildOptions.
Публичная поверхность API
Заголовок раздела «Публичная поверхность API»| Символ | Параметры | Поведение по умолчанию | Возвращает | Выбрасывает или завершается ошибкой | Примечания |
|---|---|---|---|---|---|
AstBuilder::__construct | PdfReader $reader, AstBuildOptions $options, ?AstCache $cache = null | Привязывает загруженный reader к опциям построения; кэширование необязательно | AstBuilder | — | Значение null для cache означает, что каждый вызов build() перестраивает дерево. |
AstBuilder::build | string $sourceHash (полный шестнадцатеричный SHA-256 байтов PDF) | Поиск в кэше, отклонение шифрования, путь дерева структуры, резервный путь без тегов, прикрепление ограничивающих рамок, сохранение в кэш | 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 попадает в настроенный диапазон | 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 hex хеша источника + _ + первые 16 hex хеша опций | string | — | Изменения опций автоматически аннулируют кэшированные результаты. |
AstCache::get | string $cacheKey | Декодирует JSON-полезную нагрузку через строгую проверку по каждому полю | ?AstDocument | Никогда не выбрасывает; при сбое возвращает null | Некорректные или подделанные полезные нагрузки безопасно завершаются как промах кэша. |
AstCache::set | string $cacheKey, AstDocument $document | Сохраняет JSON с TTL 24 часа, затем проверяет немедленным обратным чтением | void | AstWriteVerificationException (пространство имён Exception) | Сбой записи в бэкенд или неудачный round-trip приводит к исключению. |
AstCache::delete | string $cacheKey | Удаление по мере возможности | 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 | Удаление только в памяти; см. оговорку о скрытии данных ниже. |
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 равен null для Inserted; mutatedNode равен null для Deleted. |
MutationType | варианты enum Updated, Inserted, Deleted | Классификация на основе строк | — | — | Deleted в режиме OVERLAY скрывает содержимое; не стирает байты. |
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 исходных байтов. Конвейер таков: необязательный поиск в кэше, отклонение шифрования, путь дерева структуры, резервный путь без тегов, прикрепление ограничивающих рамок, необязательное сохранение в кэш.
Ключ кэша объединяет хеш источника с хешем AstBuildOptions. Хеш опций стабилен между экземплярами с одинаковыми значениями, поэтому идентичные входы и опции возвращают одно и то же дерево. Когда кэш не предоставлен, каждый вызов перестраивает дерево. Кэшируемые полезные нагрузки — это JSON, никогда не нативная сериализация PHP: путь чтения проверяет каждое поле и инстанцирует только типы-значения AST, поэтому отравленная запись кэша не может вызвать инъекцию объектов и деградирует до промаха кэша.
Путь дерева структуры выполняется, когда дерево структуры присутствует. Потолки ресурсов — количество узлов, глубина, дельта памяти и реальное время — применяются во время чтения дерева структуры и выбрасывают AstBuildLimitException или AstBuildTimeoutException. Если средство чтения сообщает об отсутствии дерева структуры, построитель переключается на путь без тегов: эвристический построитель, когда useHeuristic истинно, иначе простой резервный построитель. Ограничивающие рамки прикрепляются путём анализа потока содержимого каждой страницы в диапазоне; страница, поток содержимого которой не удаётся разобрать, пропускается и оставляет остальную часть дерева нетронутой.
AstNode неизменяем. Обновления дерева перестраивают затронутые узлы снизу вверх; неизменённые поддеревья возвращаются по идентичности. AstMutator следует тому же контракту: каждая мутация возвращает новый AstDocument, перестраивает только путь от корня до цели и записывает MutationEntry в общий MutationLog.
AstWriter применяет MutationLog в режиме OVERLAY как инкрементное обновление только для добавления: новые потоки содержимого наложения, обновлённые объекты страниц, секция перекрёстных ссылок, охватывающая только новые объекты, и трейлер, чей /Prev указывает на предыдущий startxref. Исходные байты остаются нетронутыми согласно модели инкрементного обновления ISO 32000-2:2020, 7.5.6. Замещающий текст, отрисовываемый для записей Updated, экранирует \, ( и ) в литеральных строках согласно ISO 32000-2:2020, 7.3.4.2.
AstPdfEmitter::emit() — симметричная обратная операция к чтению дерева структуры: деревья, произведённые средством чтения, при round-trip дают структурно эквивалентные деревья с точностью до перенумерации идентификаторов узлов и документированных классов канонизации. MCID, присутствующие на узлах, повторно эмитируются дословно и никогда не перевыделяются.
Граничные случаи и режимы сбоев
Заголовок раздела «Граничные случаи и режимы сбоев»- Зашифрованный вход отклоняется до какой-либо работы с деревом; для зашифрованных PDF нет результата с частичным деревом. Сначала расшифруйте.
- Потолки ресурсов: максимум узлов (по умолчанию 100,000), максимальная глубина (по умолчанию 200), максимальная память (по умолчанию 256 MiB), тайм-аут по реальному времени (по умолчанию 30 s). Превышение потолка выбрасывает
AstBuildLimitException; тайм-аут выбрасываетAstBuildTimeoutException, подкласс. - Диапазон страниц отсчитывается от 0 и включителен; границы null означают все страницы.
- Страница, поток содержимого которой не удаётся разобрать, пропускается во время прикрепления ограничивающих рамок; остальная часть дерева не затрагивается.
AstCache::get()никогда не выбрасывает: некорректные, подделанные или нестроковые полезные нагрузки возвращают null и вынуждают перестроение.AstCache::set()завершается с явной ошибкой, когда запись в бэкенд или немедленное обратное чтение не удаётся.AstMutatorвыбрасываетInvalidArgumentException, когда идентификатор узла не найден. Неизвестные ключи обновления молча игнорируются; применяется толькоtext_content.AstWriter::write()выбрасываетAstWriteException, когда во входных данных отсутствует заголовок%PDF-или обнаружимыйstartxref. Записи без ограничивающей рамки молча пропускаются. Страницы, которые не удаётся найти сканированием объектов — например, при сжатых потоках перекрёстных ссылок, — пропускаются; если наложение применить нельзя, входные байты возвращаются без изменений.- Вывод OVERLAY — это не скрытие данных (redaction). Белый прямоугольник и перерисованный текст добавляются; исходные байты содержимого остаются в файле и восстанавливаются прямым извлечением. Не используйте это для удаления по GDPR ст. 17 или юридического скрытия данных. Писатель режима reconstruct существует в дереве исходного кода, но помечен как внутренний, не готов к production и находится вне поддерживаемой поверхности API.
- Геометрия наложения предполагает A4 в книжной ориентации (595 x 842 pt), поскольку писатель не читает MediaBox страницы. На страницах, отличных от A4, наложение может быть слегка смещено; вывод остаётся структурно валидным.
writeAndVerify()проверяет только структуру: заголовок, завершающий%%EOFи рост вывода. Он не выполняет семантического повторного разбора изменённого документа.AstPdfEmitter::emit()выбрасываетAstEmitException, когда корень не является узлом Document или не имеет потомков. Сопутствующие записи OBJR (аннотации) в этом выпуске не эмитируются.- Этот модуль не выполняет криптографических операций и не определяет поведения, специфичного для FIPS. SHA-256 используется только как адресация по содержимому для ключей кэша.
Соответствие
Заголовок раздела «Соответствие»Путь дерева структуры читает средства логической структуры тегированного PDF, определённые ISO 32000-2; корпус RAG, доступный на момент написания, не включает пункты о логической структуре, поэтому это утверждение обосновано продуктом на основе аннотаций источника. Компоновка инкрементного обновления писателя следует ISO 32000-2:2020, 7.5.6 (цитируется ниже), а экранирование литеральных строк следует ISO 32000-2:2020, 7.3.4.2 (цитируется ниже).
Эти утверждения описывают возможности относительно цитируемых пунктов. NextPDF не имеет сертификации соответствия, и поддержка пункта не является заявлением о сертификации.
Заметки по разработке
Заголовок раздела «Заметки по разработке»- Создавайте один
AstBuilderна каждый загруженныйPdfReader. ПереиспользуйтеAstCacheмежду построениями, чтобы амортизировать разбор; конструкция ключа делает изменения опций самоаннулирующимися. - Разделяйте один
MutationLogмеждуAstMutatorиAstWriter, чтобы писатель применял ровно записанную сессию. ВызывайтеresetLog()между независимыми сессиями редактирования. - Устанавливайте
useHeuristicв true для документов без тегов, когда группировка на основе макета предпочтительнее простого резервного дерева. - Построения детерминированы для одинаковых байтов и опций; полагайтесь на это для тестов в стиле snapshot.
- Перехватывайте сбои построения через иерархию
NextPDF\Pro\Ast\Exception, а сбои записи — через иерархиюNextPDF\Pro\Ast\Writer; у них нет общего базового класса нижеRuntimeException.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов находятся вне области рассмотрения.