Stabilität: Experimentell
Retained-Page-Buffer-Erweiterung
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Per Opt-in aktivierbare Erweiterung, keine Legacy-Parität. Dieses Konstruktor-Argument existiert in Legacy-TCPDF 6.x nicht. Es ist eine NextPDF-Erweiterung. Es ist standardmäßig aus; ist es aus, verhält sich der Adapter genau wie zuvor, und
setPage()auf eine frühere Seite löstUnsupportedFeatureExceptionaus wie eh und je.
Legacy-TCPDF erlaubt Ihnen, setPage() aufzurufen, um zu einer früheren Seite
zurückzuwechseln und weiterzuzeichnen. Der streamende Adapter kann das standardmäßig
nicht — sobald eine Seite geflusht ist, ist sie weg — sodass setPage() oder
lastPage() auf eine frühere Seite UnsupportedFeatureException auslöst. Der
Retained Page Buffer ist das Opt-in, das dieses Nachfüllverhalten auf Basis des
NextPDF-Core-Retained-Page-Buffers wiederherstellt.
Den Puffer aktivieren
Abschnitt betitelt „Den Puffer aktivieren“Übergeben Sie retainedPageBuffer: true an den Adapter-Konstruktor. Bei aktivem
Puffer delegiert ein setPage()- oder lastPage()-Aufruf, der auf eine frühere
Seite zielt, an die Core-Nachfüllung, statt auszulösen:
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF(retainedPageBuffer: true);
$pdf->AddPage(); // page 1 — reserve room for a running total$pdf->Cell(0, 10, 'Invoice', ln: 1);
$pdf->AddPage(); // page 2 — line items$pdf->Cell(0, 10, 'Line items…', ln: 1);$total = 1234.56; // known only after the items are laid out
$pdf->setPage(1); // delegates to the core back-fill$pdf->Cell(0, 10, 'Grand total: ' . number_format($total, 2), ln: 1);$pdf->lastPage(); // return to the final page
$pdf->Output(__DIR__ . '/invoice.pdf', 'F');Produktionsbeispiel: eine reservierte Deckseite nachfüllen
Abschnitt betitelt „Produktionsbeispiel: eine reservierte Deckseite nachfüllen“Ein häufiger Grund, zum Puffer zu greifen, ist eine Deck- oder Übersichtsseite,
deren Zahlen erst bekannt sind, nachdem der Body umbrochen wurde — eine
Gesamtseitenzahl, eine Gesamtsumme, eine Datensatzanzahl. Reservieren Sie Seite 1 im
Voraus, rendern Sie den Body, füllen Sie dann die Deckseite mit setPage(1) nach und
setzen Sie am Ende mit lastPage() fort. Dieses Beispiel zeigt außerdem die zwei
Fail-closed-Grenzen, die Sie behandeln müssen: die UnsupportedFeatureException des
Adapters für eine Seitenzahl außerhalb des Bereichs und die Core-RetainedPageBufferIncompatibleException,
falls das Dokument zusätzlich eine inkompatible Funktion aktiviert.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\UnsupportedFeatureException;use NextPDF\Compat\Tcpdf\TCPDF;use NextPDF\Exception\Strict\RetainedPageBufferIncompatibleException;
/** * Render a multi-page report whose cover page summarises figures that are * only known once every body page has been laid out. * * @param list<array{label: string, amount: float}> $lineItems */function renderReport(array $lineItems, string $destination): void{ // Opt in to the back-fill buffer. Default-off; this is a NextPDF // extension, not legacy TCPDF parity. (Underlying core feature: 6.1.0.) $pdf = new TCPDF(retainedPageBuffer: true);
// Page 1 — the cover. Reserve it now; the summary is filled in last. $pdf->AddPage(); $pdf->Cell(0, 10, 'Quarterly report', ln: 1);
// Body pages — lay out the line items, accumulating the running total. $pdf->AddPage(); $total = 0.0; foreach ($lineItems as $item) { $total += $item['amount']; $pdf->Cell(0, 8, $item['label'] . ': ' . number_format($item['amount'], 2), ln: 1); }
// Back-fill the cover with figures known only now. setPage() delegates to // the core back-fill in retained mode; an out-of-range page number still // fails closed with UnsupportedFeatureException in BOTH modes. try { $pdf->setPage(1); } catch (UnsupportedFeatureException $e) { throw new RuntimeException('Cover page was not reserved: ' . $e->getMessage(), previous: $e); } $pdf->Cell(0, 10, 'Total: ' . number_format($total, 2), ln: 1); $pdf->Cell(0, 10, 'Line items: ' . count($lineItems), ln: 1);
// Resume appending at the final page before output. $pdf->lastPage();
// Output() drives the core build. If the document had also enabled a // back-fill-incompatible feature (signing, tagging, PDF/A, linearization, // object streams, encryption, Safe CSS mode), the core refuses here, // order-independently, with RetainedPageBufferIncompatibleException — the // back-fill can never silently corrupt such a document. try { $pdf->Output($destination, 'F'); } catch (RetainedPageBufferIncompatibleException $e) { // $e->feature names the incompatible feature, e.g. 'signature'. throw new RuntimeException( 'Back-fill is incompatible with ' . $e->feature . '; render pages in order instead.', previous: $e, ); }}Unterscheiden Sie die zwei Fehleroberflächen bewusst:
UnsupportedFeatureException(Adapter) — ein außerhalb des Bereichs liegendessetPage()- /lastPage()-Ziel oder jeder Wechsel auf eine frühere Seite, wenn der Puffer aus ist.RetainedPageBufferIncompatibleException(Core,NextPDF\Exception\Strict) — der Puffer ist an, aber mit einer Funktion kombiniert, deren Seiten-Metadaten nach einer Nachfüllung nicht neu abgeleitet werden können. Es gibt keinenRetainedPageBufferInconsistency-Typ; dies ist die einzige Inkompatibilitäts-Ausnahme, und eine Budget-Überschreitung tritt als\OverflowExceptionzutage.
Fail-closed-Grenze
Abschnitt betitelt „Fail-closed-Grenze“Der Adapter delegiert an den Core-Retained-Page-Buffer, sodass dieselben Verweigerungen gelten. Die Nachfüllung wird verweigert — reihenfolgeunabhängig und vor der Serialisierung — wenn das Dokument zusätzlich eine der folgenden Funktionen nutzt:
- Eine digitale Signatur.
- Tagged PDF (Strukturbaum).
- PDF/A.
- Linearisierung.
- Object-Stream-Packing.
- Verschlüsselung.
- Safe-CSS-Rendering-Modus.
Jede Verweigerung ist eine typisierte, fail-closed Ausnahme — niemals ein stiller Drop:
- Das Kombinieren des Puffers mit einer der obigen Funktionen löst die
Core-
RetainedPageBufferIncompatibleExceptionaus (NamespaceNextPDF\Exception\Strict,@sinceCore 6.1.0). Die Prüfung ist reihenfolgeunabhängig: Sie feuert, gleich ob die inkompatible Funktion vor oder nach dem Opt-in des Puffers konfiguriert wurde. - Ein Budget von 16 MiB unkomprimierter Bytes pro Dokument begrenzt den Puffer;
ein Überschreiten löst zur Build-Zeit
\OverflowExceptionaus, statt eine nachgefüllte Seite zu droppen.
Der Sinn der Verweigerung ist, dass eine Nachfüllung niemals stillschweigend ein signiertes oder verschlüsseltes Dokument verändern kann — die beiden lassen sich nicht gemeinsam aktivieren.
Verhaltenshinweise
Abschnitt betitelt „Verhaltenshinweise“- Standardmäßig aus. Konstruieren Sie ohne das Flag, und der Adapter ist
unverändert;
setPage()auf eine frühere Seite löst weiterhinUnsupportedFeatureExceptionaus. Dies bewahrt den Streaming-Vertrag für jeden bestehenden Aufrufer. - Keine Legacy-Parität. Legacy-TCPDF hat kein
retainedPageBuffer-Konstruktor-Flag. Dokumentieren Sie dies bei der Migration als NextPDF-Erweiterung, sodass ein späterer Leser es nicht für eine TCPDF-Funktion hält. lastPage()führt ans Ende zurück. Rufen Sie nach einer NachfüllunglastPage()auf, um das Anhängen an der finalen Seite fortzusetzen.- Planen Sie einen Modus. Wenn das Dokument signiert, getaggt, PDF/A, linearisiert, verschlüsselt oder Object-Stream-gepackt sein muss, aktivieren Sie den Puffer nicht; berechnen Sie stattdessen den Wert, den Sie nachgefüllt hätten, vorab.