稳定性: 实验性
PageBackfill:保留页面缓冲
可选启用的预览。 保留页面缓冲默认关闭。在它关闭时,写出器仍是它一向的那个流式序列化器——字节完全一致。只在你确实需要往一个较早的页面上绘制时才开启它,并先阅读下方的 fail-closed 清单。
默认情况下,写出器会流式输出页面并按顺序把它们刷出;一个页面一旦被刷出,就无法再在其上绘制。保留页面缓冲是那个可选开关,它持有已刷出的页面,使一个先前已刷出的页面能在文档被序列化之前被回填——即往一个较早的页面上绘制。经典用法是一个只有在较晚的页面排布完成后才能放置的合计或汇总框。
composer require nextpdf/core:^3保留页面缓冲随核心包一起分发。Config::withRetainedPageBuffer() 与 Document 的回填方法是 @since 6.1.0。默认仍为流式写出器。此前曾推迟此能力的 ADR-037,现已记录为已实现。
概念总览
标题为“概念总览”的章节Config::withRetainedPageBuffer() 把一份文档接入保留页面。一旦开启,Document::setActiveBackfillPage(int $pageIndex) 会把绘制重定向到一个较早的、已刷出的页面;Document::endPageBackfill() 会把绘制返回到正常的追加位置。你在这两次调用之间写入的内容会落在那个较早的页面上。该缓冲会持有页面直到 save(),因此回填会在交叉引用表与尾部被写出之前应用(ISO 32000-2 §7.5)。
Fail-closed 边界——被拒绝的组合
标题为“Fail-closed 边界——被拒绝的组合”的章节回填是一项随机访问操作,而若干文档特性假定的是仅追加、流式输出的字节。保留页面缓冲拒绝与其中任何一项组合,与顺序无关且在序列化之前进行,因此它永远不会沉默地破坏一个签章或一项符合性主张:
- 一个数字签章。
- 标签化 PDF(结构树)。
- PDF/A。
- 线性化。
- 对象流打包。
- 加密。
- Safe CSS 渲染模式。
一个逐文档的未压缩字节预算为缓冲可持有的量设上限;一份超出该预算的文档会硬性失败,而不是消耗无界的内存。流式默认仍会在调用方未经可选开关而尝试一次随机访问切换的那一刻 fail closed——开启该缓冲是获得回填的唯一途径,且按其构造它与上述特性不兼容。
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 | 把绘制返回到正常的追加位置。 |
一次违反被拒绝组合的回填尝试,会在该边界抛出一个带类型的配置异常,而非一份损坏的文档。
代码范例——快速上手
标题为“代码范例——快速上手”的章节在第一页上预留一个位置,填完文档其余部分,然后用一个在最后计算出的值回填那个预留位置。
<?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、已线性化、已加密或对象流文档,都让缓冲保持关闭——那些正是缓冲所拒绝的组合。请显式选择一条路径。
<?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()配对,使其后的内容正常追加。 - 流式默认拒绝随机访问。 没有可选开关时,一次随机访问切换会 fail closed。该缓冲是唯一受支持的路径。
保留页面缓冲以内存换取回填能力:它会持有已刷出的页面直到 save(),受逐文档未压缩字节预算约束。流式写出器的平坦内存特性只在缓冲关闭时适用。performance_budget(wall_ms: 1500、peak_mb: 128)反映了保留路径较高的内存上限。
安全性注意事项
标题为“安全性注意事项”的章节保留页面缓冲不会扩大输入面;它改变的是字节何时被序列化,而非摄取什么。它拒绝与加密和签章组合是一项安全属性:一次回填永远不能事后改变已签章或已加密的字节,因为两者不能被同时启用。字节预算为针对一份敌意文档的内存设上限。
符合性
标题为“符合性”的章节| 主张 | 标准 | 条款 |
|---|---|---|
| 写出器在保存时序列化主体、交叉引用结构与尾部。 | ISO 32000-2 | §7.5 |
这是一项预览能力。NextPDF 对已签章、已标签化、PDF/A、已线性化、已加密以及对象流文档拒绝回填缓冲,因此它不为那些配置文件通过此路径作任何符合性主张。未重制任何标准原文。
Compat(TCPDF)适配器
标题为“Compat(TCPDF)适配器”的章节TCPDF 兼容适配器把此能力暴露为一个构造器扩展。用 retainedPageBuffer: true 构造适配器,随后一个针对较早页面的 setPage() 或 lastPage() 调用会委托给核心回填,而不是抛出流式的 UnsupportedFeatureException。这个构造器参数是一项 NextPDF 扩展,而非旧版 TCPDF 对等——旧版 TCPDF 没有这样的标志。相同的 fail-closed 拒绝同样适用。适配器侧细节请参阅 compat 适配器的保留页面缓冲页。