-
Notifications
You must be signed in to change notification settings - Fork 0
Internals Architecture
This page describes the core architecture of phppdf for contributors and library maintainers. Read the Home page and the public API pages first.
Fluent builder, deferred serialization. Document accumulates pages, fonts, images, encryption settings, and metadata in memory. Nothing is written to bytes until output() (or save()) is called; that single call serializes everything in one deterministic pass via Writer/PdfWriter and the indirect-object infrastructure in Writer/Object/.
The serialization pass produces a PDF 1.7 file with:
- A cross-reference table (
xref) listing every indirect object by byte offset. - A trailer pointing at the catalog and the metadata.
- Compressed content streams (FlateDecode).
- Deterministic object numbering: the same input always produces the same bytes (which is what makes the golden-tests harness possible).
Units. All public coordinates default to millimetres; switch to PDF points via new Document(Unit::PT). Font sizes always stay in points (typographic convention). Internally, every measurement is converted to points and stored as $xxxPt floats. The Y axis is top-down in the public API; conversion to PDF native (bottom-up) happens at serialization time.
Stateful Page, single-pass content stream. Page owns a ContentStream, a font / size / leading state machine, an (x, y) cursor, and the inHeaderRender flag. cell() is the workhorse: it normalizes newlines, optionally triggers auto-page-break via Document::addPage(), then delegates rendering to Page/CellRenderer. The cursor is driven by the NextPosition enum (RIGHT / NEWLINE / BELOW).
Page lifecycle. Document::setMargins, setHeader, setFooter, setAutoPageBreak. Headers fire eagerly at addPage(); footers fire deferred at output() to allow correct (pageNumber, totalPages) substitution. Footers are guarded by $footersRendered so repeated output() calls do not double-emit. The $inHeaderRender flag on Page doubles as auto-break suppressor during header rendering and as a one-shot recursion guard for cells larger than the drawable area.
- PHP 8.4 features in use:
final readonly class, typed class constants (private const string FOO = '...'), constructor property promotion,Closureparameter types, named arguments at call sites. - Value objects are
final readonlywith named constructors (Color::hex(),Border::all(),CellPadding::symmetric(), etc.). Validation is eager in the constructor with messages that include the offending value:"Cell padding top cannot be negative, got -1". - Public API exposes float coordinates in the document unit. Internal helpers ending in
Ptoperate in points. Never mix. - Error handling is fail-fast: throw
PdfException(or subclass) at the boundary. - PHPStan runs at
level: maxonsrc/andtests/. New code must pass with zero errors (no@phpstan-ignore); prefer adding a real accessor over silencing anonlyWrittenproperty. - PHPUnit is configured with
failOnWarning="true"andfailOnRisky="true": a warning is a failure. - ASCII only in code, comments, and commit messages (no em-dash, no curly quotes).
MIT licensed. Source on GitHub - if phppdf helps you, you can buy me a coffee.