Ga naar inhoud
getnextpdf.com

Waarom je PDF-engine in PHP thuishoort, niet in een sidecar

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

Er zijn twee plekken waar een PDF kan worden gemaakt: binnen je PHP-proces, of ergens anders dat je moet beheren. NextPDF maakt hem binnenin. Deze pagina is het pleidooi voor die keuze — waarom een in-process-engine doorgaans de juiste standaard is, en wat het “ergens anders”-patroon werkelijk kost zodra het in productie is.

Dit is de architectuurhoek, niet de framework-hoek. Hoe dezelfde engine Laravel, Symfony, CodeIgniter en standalone code bereikt is een ander verhaal, verteld in one engine, every framework.

Een PDF-functie begint zelden als een systeem dat je beheert. Het begint als een regel in een controller: render deze factuur, retourneer dat rapport. Het sidecar-patroon verandert die regel in infrastructuur. Om het document te tekenen draai je nu een tweede ding — een externe binary, een headless browser, een afzonderlijke microservice — en alles wat dat tweede ding nodig heeft, wordt ook jouw probleem: zijn versie, zijn geheugen, zijn container, zijn netwerk, zijn faalwijzen, zijn oproep om 2 uur ‘s nachts.

De kosten zijn onzichtbaar in de demo en onvermijdelijk in productie. Een document-engine die in je proces leeft, heeft er niets van. De vraag is niet “kan een sidecar een PDF maken” — natuurlijk kan dat. Het is “wat heb je je verplicht te beheren om daar te komen, en had je dat nodig.”

  • In-process betekent geen tweede runtime. NextPDF tekent de PDF binnen dezelfde PHP-worker die het verzoek afhandelde. Er is geen subproces om af te splitsen, geen service om uit te rollen, en niets extra’s om in leven te houden.
  • Een sidecar voegt een operationeel oppervlak toe dat je niet had. Een gebundelde browser of externe binary brengt zijn eigen versie, zijn eigen security-voetafdruk en zijn eigen container — die je nu allemaal patcht en monitort.
  • Procesgrenzen zijn waar dingen misgaan. Cold starts, time-outs, broze inter-procescommunicatie en data die je proces verlaat, zijn faalwijzen die een in-process-aanroep simpelweg niet heeft.
  • In-process is testbaar en deterministisch. De engine is getypeerd PHP die je kunt unit-testen, mocken en over kunt redeneren — geen ondoorzichtige renderer die je alleen kunt onderzoeken door hem te draaien en naar de uitvoer te kijken.
  • Een echte browser heeft nog steeds echte toepassingen. Voor pixelgetrouwe weergave van willekeurige moderne webpagina’s is een headless browser het eerlijke gereedschap — en NextPDF kan er weloverwogen naar delegeren. Het is een naad, niet de standaard.

Houd de twee architecturen naast elkaar. Het in-process-pad is een functieaanroep. Het sidecar-pad is een gedistribueerd systeem in het klein — en elke pijl tussen de vakken ervan is een plek die onafhankelijk van je code faalt.

  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.

Geen tweede runtime om te beheren. Het sidecar-patroon is twee systemen die het kostuum van één functie dragen. Een gebundelde wkhtmltopdf, een headless Chromium-service, een afzonderlijke render-microservice — elk is een runtime met een eigen releasecadans en eigen bugs. Je erft het allemaal. De in-process-engine levert als Composer-dependency; hij wordt geüpgraded zoals elke andere bibliotheek in je composer.json, zonder daemon, image of socket toegevoegd aan je deployment.

Versie-drift en een breder security-oppervlak. Een gebundelde browser is een grote, snel bewegende codebase met een gestage stroom security-advisories. Pin hem en hij verrot; volg hem en hij churnt. Hoe dan ook is het het hele webplatform van een renderer dat in je supply chain zit om één document te voeden. Een in-process-PHP-engine is een gerichte bibliotheek code die je kunt lezen; zijn security-oppervlak is de PHP die je toch al draait, geen tweede platform dat je nu ook draait.

Data blijft binnen je procesgrens. Wanneer je uitwijkt, kruist de documentinhoud — die vaak precies de gevoelige data is die een PDF bestaat om te dragen — een grens. Het wordt geschreven naar een pipe, een argument, een tijdelijk bestand, of een netwerksocket naar een service. Elk daarvan is een plek om te lekken, om per ongeluk te loggen, of om achter te laten. In-process verlaat de data nooit de worker die ze bezit. De blast radius is één proces, geen vloot.

Broze plumbing, cold starts en time-outs. Inter-proces- en netwerkaanroepen falen op manieren die een functieaanroep niet kan: het subproces dat niet startte, de socket die bleef hangen, de time-out die je verkeerd gokte, de cold start onder een verkeerspiek. Elk vergt een retry-beleid, een circuit breaker en een budget. Een in-process-render retourneert ofwel bytes ofwel werpt een getypeerde exceptie die je op de volgende regel opvangt. Er is geen gedeeltelijke netwerktoestand om te verzoenen.

Observability en testen worden lastiger over de grens heen. Een fout in een sidecar arriveert als een exit-code, een afgekapte logregel, of een 500 van een service die je niet beheert. Hem reproduceren betekent die hele omgeving reproduceren. Een in-process-engine is observeerbaar met de gereedschappen die je toch al gebruikt — een stack trace, een debugger, een profiler — en hij is testbaar zoals de rest van je PHP. Die testbaarheid is een benoemde software-kwaliteitseigenschap: ISO/IEC 25010 plaatst haar onder onderhoudbaarheid (Spec: ISO/IEC 25010:2023, §3.7), en een in-process-bibliotheek voldoet er veel directer aan dan een renderer die je alleen kunt uitoefenen door hem op te starten.

De PDF waarop die tests asserteren is een gedefinieerde structuur, geen black box. Een PDF-bestand heeft een gespecificeerde object- en bestandsindeling (Spec: ISO 32000-2, §7), en een in-process-engine zendt die structuur uit vanuit code die je kunt lezen — dus een golden-file- of structurele test controleert bytes die een bekende functie produceerde, in plaats van de uitvoer van een extern programma dat je alleen kunt observeren.

Het hele punt past in een handvol regels. Er is geen client, geen base-URL, geen health check en geen retry-beleid — omdat er geen tweede systeem is.

<?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();

Vergelijk de vorm van de sidecar-versie — niet zijn code, zijn operationele vorm. Het vergt een binary of service die geïnstalleerd en bereikbaar is, een verzoek dat geserialiseerd en verzonden wordt, een gekozen time-out, een faalpad voor wanneer de renderer koud of down is, en het resultaat dat terug gemarshald wordt. Niets daarvan zit in het bovenstaande fragment, omdat niets ervan bestaat wanneer de engine een bibliotheek is.

De frequente aanname is dat “echte” PDF-weergave een browser moet betekenen, dus in-process moet de speelgoedversie zijn. Dat heeft de afweging omgedraaid. Een browser is het juiste gereedschap wanneer je exacte, pixelgetrouwe weergave van willekeurige moderne webinhoud nodig hebt. Het is de verkeerde standaard voor het documentvormige werk dat de meeste teams daadwerkelijk doen — facturen, rapporten, afschriften, contracten — waar de lay-out bekend is, de data van jou is, en correctheid wordt gecontroleerd door een validator, niet met het oog. Voor dat werk koopt het operationele gewicht van een sidecar je niets dat de in-process-engine je niet al geeft, en kost het je alles in de secties hierboven.

Het spiegelmisverstand is het misverstand dat deze pagina zorgvuldig vermijdt te begaan: claimen dat een in-process-engine “het hele web” weergeeft zoals een browser. Dat doet hij niet, en NextPDF doet niet alsof. Zijn in-process-HTML-pijplijn is een specificatie-aligned subset gericht op documentlay-out, met gedocumenteerde grenzen — de eerlijke scope wordt uiteengezet in the HTML pipeline. Wanneer je werkelijk volledige browser-getrouwheid nodig hebt, is dat een weloverwogen, opt-in delegatie, geen stille terugval.

In-process is de juiste standaard. Het is geen universele claim dat een subproces nooit gerechtvaardigd is. Waar een document werkelijk exacte weergave van willekeurige moderne CSS vereist die de in-process-engine niet dekt, is delegeren aan een headless browser de juiste keuze — en NextPDF ondersteunt dat pad weloverwogen, met zijn netwerktoegang beperkt, als een naad in plaats van de standaard. De twee zijn geen rivalen; het zijn verschillende gereedschappen voor verschillende taken.

Deze pagina beargumenteert de architectuur, niet een CSS-ondersteuningsmatrix. Welke HTML en CSS de in-process-pijplijn precies dekt, wordt gedefinieerd door de code van de engine en zijn conformiteitstests, en is gedocumenteerd bij die pijplijn — niet hier beloofd. “In-process” beschrijft het standaard weergavepad; het is geen claim dat elk mogelijk pad een subproces vermijdt.

Het mogelijkhedenoppervlak blijft eenvoudig: de in-process-engine is Core, en het browser-delegatiepad is een optionele uitbreiding, onafhankelijk van editie.

Where the PDF is rendered — edition availability
EditionAvailability
CoreCore renders PDF in-process in PHP — no subprocess, binary, or sidecar by default.
ProThe headless-browser delegation path is an optional add-on extension, independent of edition tier.
EnterpriseThe headless-browser delegation path is an optional add-on extension, independent of edition tier.
  • The HTML pipeline — de eerlijke scope van de in-process-engine, en precies wanneer delegeren aan een browser juist is.
  • One engine, every framework — de complementaire as: hoe dezelfde in-process-engine elk PHP-framework bereikt zonder een andere bibliotheek per stack.
  • Operating NextPDF in production — hoe het draaien van een in-process-engine er dag in dag uit uitziet, zonder extra runtime om te beheren.
  • Memory and streaming — hoe de engine in-process-generatie begrensd houdt onder belasting.
  • In-process-generatie — de PDF produceren binnen dezelfde PHP-worker die het verzoek afhandelt, zonder subproces, socket of externe service.
  • Sidecar — een afzonderlijke runtime die naast je applicatie draait om één taak te doen; hier een externe binary, headless browser of microservice die de PDF buiten je proces weergeeft.
  • Cold start — de latentie- en resourcepiek die optreedt wanneer een subproces of service vanaf niets gestart moet worden voordat het het eerste verzoek kan bedienen.
  • IPC — inter-procescommunicatie: de pipes, sockets, tijdelijke bestanden of netwerkaanroepen die gebruikt worden om data van en naar een afzonderlijk proces te geven, en een terugkerende bron van broze, moeilijk te debuggen fouten.
  • Browser-delegatienaad — het optionele, opt-in pad dat een render overhandigt aan een headless browser voor exacte getrouwheid, met subresource-netwerktoegang geblokkeerd; een weloverwogen keuze, niet de standaard.