安定性: 実験的
PageBackfill:保持ページバッファ
オプトインのプレビュー。 保持ページバッファはデフォルトでオフです。オフのとき、 ライターは従来どおりのストリーミングシリアライザーです — バイト単位で同一です。先行ページに本当に描画する必要があるときに限ってオンにし、まず下記のフェイルクローズ一覧を読んでください。
デフォルトでは、ライターはページをストリーミングし、順にフラッシュします。いったんページがフラッシュされると、再度描画することはできません。保持ページバッファは、フラッシュ済みのページを保持し、すでにフラッシュされた先行ページをバックフィル — 先行ページに描画 — できるようにするオプトインで、これはドキュメントがシリアライズされる前に行われます。典型的な用途は、後続ページがレイアウトされた後にしか配置できない合計欄やサマリーボックスです。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/core:^3保持ページバッファは core パッケージに同梱されています。Config::withRetainedPageBuffer() と
Document のバックフィルメソッドは @since 6.1.0 です。デフォルトは引き続きストリーミングライターです。以前この機能を延期していた ADR-037 は、実装済みとして記録されました。
概念の概要
「概念の概要」という見出しのセクションConfig::withRetainedPageBuffer() は、ドキュメントを保持ページにオプトインさせます。オンになると、
Document::setActiveBackfillPage(int $pageIndex) が描画を、すでにフラッシュされた先行ページへリダイレクトし、Document::endPageBackfill() が描画を通常の追記位置へ戻します。この 2 つの呼び出しの間に書くコンテンツは先行ページに配置されます。バッファは save() までページを保持するため、バックフィルは相互参照テーブルとトレーラーが書き込まれる前に適用されます(ISO 32000-2 §7.5)。
フェイルクローズ境界 — 拒否される組み合わせ
「フェイルクローズ境界 — 拒否される組み合わせ」という見出しのセクションバックフィルはランダムアクセス操作であり、いくつかのドキュメント機能は追記専用のストリーミングされたバイトを前提としています。保持ページバッファは、それらのいずれとの組み合わせも、順序に依存せず、かつシリアライズの前に拒否するため、署名や適合性の主張を暗黙のうちに壊すことは決してありません。
- デジタル署名。
- タグ付き PDF(構造ツリー)。
- PDF/A。
- 線形化。
- オブジェクトストリームのパッキング。
- 暗号化。
- Safe CSS レンダリングモード。
ドキュメントごとの非圧縮バイト予算が、バッファが保持できる量を上限付けます。それを超えるドキュメントは、無制限のメモリを消費するのではなくハードフェイルします。ストリーミングのデフォルトは、オプトインなしに呼び出し側がランダムアクセスの切り替えを試みた瞬間に、依然としてフェイルクローズします。バッファをオンにすることがバックフィルを得る唯一の方法であり、それは構造上、上記の機能とは非互換です。
API サーフェス
「API サーフェス」という見出しのセクション| シンボル | 場所 | 役割 |
|---|---|---|
Config::withRetainedPageBuffer(bool $enabled = true): self | src/Core/Config.php | ドキュメントを保持ページバッファにオプトインさせる。 |
Document::setActiveBackfillPage(int $pageIndex): static | src/Core/Document.php | 描画を、すでにフラッシュされた先行ページへリダイレクトする。 |
Document::endPageBackfill(): static | src/Core/Document.php | 描画を通常の追記位置へ戻す。 |
拒否される組み合わせに違反するバックフィルの試みは、破損したドキュメントではなく、境界で型付きの設定例外を送出します。
コードサンプル — クイックスタート
「コードサンプル — クイックスタート」という見出しのセクション1 ページ目に枠を予約し、ドキュメントの残りを埋めてから、最後に計算した値で予約済みの枠をバックフィルします。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;use NextPDF\Core\Document;
$config = (new Config())->withRetainedPageBuffer();
$doc = Document::createStandalone($config);$doc->addPage(); // page 0 — leaves room for a grand total$doc->writeHtml('<h1>Invoice</h1>');
$doc->addPage(); // page 1 — line items$doc->writeHtml('<p>Line items…</p>');$total = 1234.56; // computed after laying out the items
$doc->setActiveBackfillPage(0); // draw back onto page 0$doc->writeHtml('<p>Grand total: ' . number_format($total, 2) . '</p>');$doc->endPageBackfill();
$doc->save(__DIR__ . '/invoice.pdf');コードサンプル — 本番
「コードサンプル — 本番」という見出しのセクション署名済み、タグ付き、PDF/A、線形化済み、暗号化済み、またはオブジェクトストリームのドキュメントでは、 バッファをオフのままにしてください — それらはまさにバッファが拒否する組み合わせです。1 つのパスを明示的に選択してください。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;use NextPDF\Core\Document;
function renderReport(bool $needsBackfill, bool $mustBeSigned): Document{ if ($needsBackfill && $mustBeSigned) { // The buffer refuses to combine with signing. Resolve the requirement // before building: pre-compute the value, or sign a separate pass. throw new \LogicException('Back-fill and signing are mutually exclusive.'); }
$config = new Config(); if ($needsBackfill) { $config = $config->withRetainedPageBuffer(); }
return Document::createStandalone($config);}エッジケースと落とし穴
「エッジケースと落とし穴」という見出しのセクション- オフはバイト単位で同一です。 バッファがオフのとき、ライターは従来どおりストリーミングします。
- 署名、タグ付け、PDF/A、線形化、オブジェクトストリーム、暗号化、Safe CSS モードとは相互排他です。 拒否は順序に依存せず、シリアライズの前に発火します。ドキュメントをどちらか一方のモードで計画してください。
- バイト予算はハードフェイルします。 保持バッファは有界です。非圧縮バイト予算を超えるドキュメントは、際限なく増大するのではなく失敗します。
- 呼び出しをペアにしてください。 すべての
setActiveBackfillPage()はendPageBackfill()と対応させ、後続のコンテンツが正常に追記されるようにすべきです。 - ストリーミングのデフォルトはランダムアクセスを拒否します。 オプトインなしでは、ランダムアクセスの切り替えはフェイルクローズします。バッファが唯一サポートされるパスです。
パフォーマンス
「パフォーマンス」という見出しのセクション保持ページバッファは、メモリとバックフィル機能をトレードオフします。save() までフラッシュ済みページを保持し、ドキュメントごとの非圧縮バイト予算で有界化されます。ストリーミングライターのフラットなメモリプロファイルは、バッファがオフのときにのみ適用されます。performance_budget(wall_ms: 1500、
peak_mb: 128)は、保持パスのより高いメモリ上限を反映しています。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクション保持ページバッファは入力サーフェスを拡大しません。バイトがいつシリアライズされるかを変えるのであって、 何が取り込まれるかは変えません。暗号化や署名との組み合わせを拒否することは安全性の特性です。すなわち、 バックフィルが後から署名済みまたは暗号化済みのバイトを書き換えることは決してできません。両者を同時に有効化できないからです。バイト予算は、敵対的なドキュメントに対してメモリを有界化します。
| 記述 | 仕様 | 条項 |
|---|---|---|
| ライターは保存時に本体、相互参照構造、トレーラーをシリアライズする。 | ISO 32000-2 | §7.5 |
これはプレビュー機能です。NextPDF は、署名済み、タグ付き、PDF/A、線形化済み、暗号化済み、オブジェクトストリームのドキュメントに対してバックフィルバッファを拒否するため、このパスを通じてそれらのプロファイルに関する適合性の主張は行いません。規格本文の複製は行っていません。
互換(TCPDF)アダプター
「互換(TCPDF)アダプター」という見出しのセクションTCPDF 互換アダプターは、この機能をコンストラクター拡張として公開します。アダプターを
retainedPageBuffer: true で構築すると、先行ページを対象とする setPage() または lastPage() の呼び出しは、ストリーミングの UnsupportedFeatureException を送出するのではなく、コアのバックフィルへ委譲します。このコンストラクター引数は NextPDF の拡張であり、レガシー TCPDF とのパリティではありません —
レガシー TCPDF にはそのようなフラグはありません。同じフェイルクローズの拒否が適用されます。アダプター側の詳細については、互換アダプターの保持ページバッファのページを参照してください。