Zum Inhalt springen
getnextpdf.com

Warum Ihre PDF-Engine in PHP gehört, nicht in einen Sidecar

Spec: ISO/IEC 25010:2023, §3.7Spec: ISO 32000-2, §7

Es gibt zwei Orte, an denen ein PDF erzeugt werden kann: in Ihrem PHP-Prozess oder irgendwo anders, das Sie betreiben müssen. NextPDF erzeugt es innen. Auf dieser Seite steht das Argument für diese Wahl — warum eine prozessinterne Engine in der Regel die richtige Voreinstellung ist und was das „irgendwo anders“-Muster tatsächlich kostet, sobald es in der Produktion ist.

Das ist die Architektur-Perspektive, nicht die Framework-Perspektive. Wie dieselbe Engine Laravel, Symfony, CodeIgniter und eigenständigen Code erreicht, ist eine andere Geschichte, erzählt in Eine Engine, jedes Framework.

Ein PDF-Feature beginnt selten als ein System, das Sie betreiben. Es beginnt als eine Zeile in einem Controller: rendere diese Rechnung, gib jenen Bericht zurück. Das Sidecar-Muster verwandelt diese Zeile in Infrastruktur. Um das Dokument zu zeichnen, betreiben Sie nun ein zweites Ding — ein externes Binary, einen Headless-Browser, einen separaten Microservice —, und alles, was dieses zweite Ding braucht, wird ebenfalls Ihr Problem: seine Version, sein Speicher, sein Container, sein Netzwerk, seine Fehlermodi, sein Bereitschaftsalarm um 2 Uhr nachts.

Die Kosten sind in der Demo unsichtbar und in der Produktion unvermeidlich. Eine Dokument-Engine, die in Ihrem Prozess lebt, hat nichts davon. Die Frage lautet nicht „Kann ein Sidecar ein PDF erzeugen?“ — natürlich kann er das. Sie lautet „Was haben Sie sich zu betreiben verpflichtet, um dorthin zu gelangen, und mussten Sie das?“.

  • Prozessintern bedeutet keine zweite Laufzeitumgebung. NextPDF zeichnet das PDF innerhalb desselben PHP-Workers, der die Anfrage bearbeitet hat. Es gibt keinen Subprozess zu starten, keinen Dienst zu deployen und nichts Zusätzliches am Leben zu halten.
  • Ein Sidecar fügt eine betriebliche Angriffsfläche hinzu, die Sie nicht hatten. Ein mitgelieferter Browser oder ein externes Binary bringt seine eigene Version, seinen eigenen Sicherheits-Fußabdruck und seinen eigenen Container mit — die Sie nun alle patchen und überwachen.
  • Prozessgrenzen sind dort, wo Dinge schiefgehen. Kaltstarts, Timeouts, brüchige prozessübergreifende Verdrahtung und Daten, die Ihren Prozess verlassen, sind Fehlermodi, die ein prozessinterner Aufruf schlicht nicht hat.
  • Prozessintern ist testbar und deterministisch. Die Engine ist typisiertes PHP, das Sie unit-testen, mocken und durchdenken können — kein undurchsichtiger Renderer, den Sie nur dadurch ergründen können, dass Sie ihn ausführen und die Ausgabe betrachten.
  • Ein echter Browser hat weiterhin echte Einsatzzwecke. Für pixelgetreues Rendering beliebiger moderner Webseiten ist ein Headless-Browser das ehrliche Werkzeug — und NextPDF kann bewusst an einen delegieren. Es ist eine Naht, nicht die Voreinstellung.

Halten Sie die beiden Architekturen nebeneinander. Der prozessinterne Pfad ist ein Funktionsaufruf. Der Sidecar-Pfad ist ein verteiltes System im Kleinen — und jeder Pfeil zwischen seinen Kästen ist eine Stelle, die unabhängig von Ihrem Code ausfällt.

  1. In-process: call the enginewriteHtml() or the document API runs inside the current PHP worker — no subprocess, no socket.
  2. In-process: receive PDF bytesThe engine returns native PDF content directly; nothing left the process.
  3. Sidecar: serialize and shipMarkup or a request is marshalled out of your process to a binary, browser, or remote service.
  4. Sidecar: cross the boundaryA process spawn or network hop — with a cold start, a timeout, and an IPC contract that can break.
  5. Sidecar: run a second runtimeAn external renderer with its own version, memory profile, and security surface to operate and patch.
  6. Sidecar: deserialize backMarshal the result back in and translate the renderer’s errors into yours.
The in-process path versus the sidecar path. In-process, the PDF is produced by a typed call inside the same PHP worker and returned directly. The sidecar path adds a serialization step, a process or network boundary, an external runtime with its own version and footprint, and a deserialization step back — each a distinct failure mode the in-process call does not have.

Keine zweite Laufzeitumgebung zu betreiben. Das Sidecar-Muster sind zwei Systeme im Kostüm eines Features. Ein mitgeliefertes wkhtmltopdf, ein Headless-Chromium-Dienst, ein separater Render-Microservice — jedes ist eine Laufzeitumgebung mit ihrem eigenen Release-Takt und ihren eigenen Bugs. Sie erben das alles. Die prozessinterne Engine wird als Composer-Abhängigkeit ausgeliefert; sie wird so aktualisiert, wie jede andere Bibliothek in Ihrer composer.json, ohne dass Ihrem Deployment ein Daemon, ein Image oder ein Socket hinzugefügt wird.

Versionsdrift und eine breitere Sicherheits-Angriffsfläche. Ein mitgelieferter Browser ist eine große, sich schnell bewegende Codebasis mit einem stetigen Strom von Sicherheitshinweisen. Pinnen Sie ihn, und er verrottet; verfolgen Sie ihn, und er ist in ständiger Bewegung. So oder so ist es die gesamte Webplattform eines Renderers, die in Ihrer Lieferkette sitzt, um ein Dokument zu befüllen. Eine prozessinterne PHP-Engine ist eine fokussierte Bibliothek aus Code, den Sie lesen können; ihre Sicherheits-Angriffsfläche ist das PHP, das Sie ohnehin schon betreiben, keine zweite Plattform, die Sie nun ebenfalls betreiben.

Daten bleiben innerhalb Ihrer Prozessgrenze. Wenn Sie auslagern, überquert der Dokumentinhalt — der oft genau die sensiblen Daten sind, zu deren Transport ein PDF existiert — eine Grenze. Er wird in eine Pipe, ein Argument, eine temporäre Datei oder einen Netzwerk-Socket zu einem Dienst geschrieben. Jede davon ist eine Stelle, an der Daten leaken, versehentlich protokolliert oder zurückgelassen werden können. Prozessintern verlassen die Daten nie den Worker, dem sie gehören. Der Wirkungsradius ist ein Prozess, keine Flotte.

Brüchige Verdrahtung, Kaltstarts und Timeouts. Prozessübergreifende und Netzwerkaufrufe scheitern auf Arten, die ein Funktionsaufruf nicht kann: der Subprozess, der nicht startete, der Socket, der hing, das Timeout, das Sie falsch geraten haben, der Kaltstart unter einer Verkehrsspitze. Jedes braucht eine Retry-Policy, einen Circuit-Breaker und ein Budget. Ein prozessinternes Rendern gibt entweder Bytes zurück oder wirft eine typisierte Ausnahme, die Sie in der nächsten Zeile fangen. Es gibt keinen partiellen Netzwerkzustand abzugleichen.

Observability und Testen werden über die Grenze hinweg schwerer. Ein Fehlschlag in einem Sidecar kommt als Exit-Code, als abgeschnittene Logzeile oder als 500 von einem Dienst an, den Sie nicht kontrollieren. Ihn zu reproduzieren bedeutet, diese ganze Umgebung zu reproduzieren. Eine prozessinterne Engine ist mit den Werkzeugen beobachtbar, die Sie ohnehin schon nutzen — ein Stacktrace, ein Debugger, ein Profiler —, und sie ist so testbar, wie der Rest Ihres PHP. Diese Testbarkeit ist eine benannte Software-Qualitätseigenschaft: ISO/IEC 25010 ordnet sie unter Wartbarkeit ein (Spec: ISO/IEC 25010:2023, §3.7), und eine prozessinterne Bibliothek erfüllt sie weit direkter als ein Renderer, den Sie nur durch dessen Starten ausüben können.

Das PDF, gegen das diese Tests prüfen, ist eine definierte Struktur, keine Black Box. Eine PDF-Datei hat ein spezifiziertes Objekt- und Datei-Layout (Spec: ISO 32000-2, §7), und eine prozessinterne Engine gibt diese Struktur aus Code aus, den Sie lesen können — sodass ein Golden-File- oder Struktur-Test Bytes prüft, die eine bekannte Funktion erzeugt hat, statt der Ausgabe eines externen Programms, das Sie nur beobachten können.

Der ganze Punkt passt in eine Handvoll Zeilen. Es gibt keinen Client, keine Basis-URL, keinen Health-Check und keine Retry-Policy — weil es kein zweites System gibt.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// The engine runs inside this very process. No subprocess is spawned,
// no socket is opened, and the report data never leaves the worker.
$document = Document::createStandalone();
$document->setTitle('Quarterly Report');
$document->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">Quarterly Report</h1>
<p>Rendered <strong>in-process</strong> by PHP — no browser, no sidecar.</p>
HTML;
$document->writeHtml($html);
// PDF bytes are returned directly. There is no boundary to marshal across,
// so there is no timeout, cold start, or deserialization step to handle.
$bytes = $document->getPdfData();

Stellen Sie die Gestalt der Sidecar-Variante gegenüber — nicht ihren Code, ihre betriebliche Gestalt. Sie braucht ein Binary oder einen Dienst, der installiert und erreichbar ist, eine serialisierte und gesendete Anfrage, ein gewähltes Timeout, einen Fehlerpfad für den Fall, dass der Renderer kalt oder ausgefallen ist, und das zurückgereichte Ergebnis. Nichts davon steht im Ausschnitt oben, weil nichts davon existiert, wenn die Engine eine Bibliothek ist.

Die häufige Annahme ist, dass „echtes“ PDF-Rendering einen Browser bedeuten müsse, sodass prozessintern die Spielzeugvariante sein müsse. Das hat den Kompromiss verkehrt herum. Ein Browser ist das richtige Werkzeug, wenn Sie exaktes, pixelgetreues Rendering beliebiger moderner Webinhalte brauchen. Er ist die falsche Voreinstellung für die dokumentförmige Arbeit, die die meisten Teams tatsächlich tun — Rechnungen, Berichte, Auszüge, Verträge —, bei der das Layout bekannt ist, die Daten Ihre sind und die Korrektheit von einem Validator geprüft wird, nicht mit dem Auge. Für diese Arbeit erkauft Ihnen das betriebliche Gewicht eines Sidecars nichts, was die prozessinterne Engine nicht ohnehin schon gibt, und kostet Sie alles in den Abschnitten oben.

Das Spiegelmissverständnis ist das, das diese Seite sorgfältig nicht begeht: zu behaupten, eine prozessinterne Engine rendere „das ganze Web“ wie ein Browser. Das tut sie nicht, und NextPDF gibt das nicht vor. Ihre prozessinterne HTML-Pipeline ist eine spezifikationskonforme Teilmenge mit Fokus auf Dokument-Layout, mit dokumentierten Grenzen — der ehrliche Umfang ist in Die HTML-Pipeline dargelegt. Wenn Sie wirklich volle Browser-Treue brauchen, ist das eine bewusste, ausdrücklich gewählte Delegation, kein stiller Rückfall.

Prozessintern ist die richtige Voreinstellung. Es ist keine universelle Behauptung, dass ein Subprozess nie gerechtfertigt sei. Wo ein Dokument wirklich exaktes Rendering beliebigen modernen CSS erfordert, das die prozessinterne Engine nicht abdeckt, ist die Delegation an einen Headless-Browser die richtige Wahl — und NextPDF unterstützt diesen Pfad bewusst, mit eingeschränktem Netzwerkzugriff, als Naht statt als Voreinstellung. Die beiden sind keine Rivalen; sie sind unterschiedliche Werkzeuge für unterschiedliche Aufgaben.

Diese Seite argumentiert die Architektur, keine CSS-Support-Matrix. Genau welches HTML und CSS die prozessinterne Pipeline abdeckt, ist durch den Code der Engine und ihre Konformitätstests definiert und ist mit dieser Pipeline dokumentiert — nicht hier versprochen. „Prozessintern“ beschreibt den voreingestellten Rendering-Pfad; es ist keine Behauptung, dass jeder mögliche Pfad einen Subprozess vermeidet.

Die Fähigkeitsfläche bleibt einfach: Die prozessinterne Engine ist Core, und der Browser-Delegationspfad ist eine optionale Erweiterung, unabhängig von der Edition.

Where the PDF is rendered — edition availability
EditionAvailability
CoreCore rendert PDF prozessintern in PHP — kein Subprozess, kein Binary, kein Sidecar in der Voreinstellung.
ProDer Pfad für die Headless-Browser-Delegation ist eine optionale Zusatzerweiterung, unabhängig von der Edition-Stufe.
EnterpriseDer Pfad für die Headless-Browser-Delegation ist eine optionale Zusatzerweiterung, unabhängig von der Edition-Stufe.
  • Die HTML-Pipeline — der ehrliche Umfang der prozessinternen Engine und genau wann die Delegation an einen Browser richtig ist.
  • Eine Engine, jedes Framework — die ergänzende Achse: wie dieselbe prozessinterne Engine jedes PHP-Framework erreicht, ohne eine andere Bibliothek pro Stack.
  • NextPDF im Produktivbetrieb betreiben — wie der Betrieb einer prozessinternen Engine im Alltag aussieht, ohne eine zusätzliche Laufzeitumgebung zu betreiben.
  • Speicher und Streaming — wie die Engine die prozessinterne Erzeugung unter Last begrenzt hält.
  • Prozessinterne Erzeugung — das Erzeugen des PDF innerhalb desselben PHP-Workers, der die Anfrage bearbeitet, ohne Subprozess, Socket oder externen Dienst.
  • Sidecar — eine separate Laufzeitumgebung, die neben Ihrer Anwendung läuft, um eine Aufgabe zu erledigen; hier ein externes Binary, ein Headless-Browser oder ein Microservice, der das PDF außerhalb Ihres Prozesses rendert.
  • Kaltstart — die Latenz- und Ressourcenspitze, die entsteht, wenn ein Subprozess oder Dienst aus dem Nichts gestartet werden muss, bevor er die erste Anfrage bedienen kann.
  • IPC — Inter-Prozess-Kommunikation: die Pipes, Sockets, temporären Dateien oder Netzwerkaufrufe, die genutzt werden, um Daten an einen und von einem separaten Prozess zu übergeben, und eine wiederkehrende Quelle brüchiger, schwer zu debuggender Fehlschläge.
  • Browser-Delegationsnaht — der optionale, ausdrücklich gewählte Pfad, der ein Rendern für exakte Treue an einen Headless-Browser übergibt, mit blockiertem Netzwerkzugriff auf Subressourcen; eine bewusste Wahl, nicht die Voreinstellung.