Support: shared utilities + Clock + Sleeper
At a glance
Section titled “At a glance”The Support module contains shared utilities the engine uses internally. It also exposes a small public surface: the PHP Standards Recommendation 20 (PSR-20) system clock, the warning collection pipeline, and Portable Document Format (PDF) serialization primitives. Most of the namespace is internal infrastructure. This page documents the parts you can rely on and marks the internal-only parts.
Install
Section titled “Install”composer require nextpdf/core:^3Conceptual overview
Section titled “Conceptual overview”Clock (PSR-20). SystemClock implements Psr\Clock\ClockInterface. Its
now() method returns the current time as a DateTimeImmutable. The PSR-20
model defines a clock interface with one read operation, which returns the
current time as an immutable date-time value (PSR-20 psr_20_clock#2.1).
SystemClock is the default; the engine uses it when you do not inject a
clock. For fixed time in tests, inject a frozen clock that implements the same
interface. Pair the clock with Config::deterministic when you need
byte-identical output.
Warning pipeline. WarningCollector is the main in-memory transport for
non-fatal rendering issues. The engine appends a Warning for each
deterministic degradation, such as a squeezed table column, an unresolved font,
or a missing glyph. After generation, you read warnings through
Document::getWarnings(). A Warning is an immutable value object. It carries
a WarningCode, a WarningSeverity (warning or degraded), the page, the
element type, the feature id, a degraded-parity flag, a message, a
DegradationImpact, and an optional capability id. WarningCode is a
string-backed enum of stable identifiers. The identifiers use the NEXTPDF_W_
prefix, such as NEXTPDF_W_FONT_UNRESOLVED, so you can match them safely in
tests. addWithPolicy() enforces the active DegradationPolicy. Under a
strict policy, a compliance, semantic, or blocking impact throws
DegradedException. Under a balanced policy, only a blocking impact throws. A
permissive policy never throws.
PDF primitives. PdfStringEscaper is the single source of truth for PDF
string and name escaping. escapeLiteral() escapes the characters required in
a PDF literal string: reverse solidus, parentheses, carriage return (CR), line
feed (LF), horizontal tab (HT), backspace (BS), and form feed (FF). It also
strips the NUL byte. escapeName() hex-encodes bytes outside the printable
American Standard Code for Information Interchange (ASCII) range and bytes in
the PDF delimiter set for a name object. BinaryBuffer is a write-optimized
binary accumulator for PDF objects and streams. In streaming mode, it spills to
a php://temp handle for large documents. It also supports the byte-range
operations that signature embedding needs. PdfOperators holds the
content-stream operator format strings for paths, text, graphics state, and
fonts. The drawing and parser layers share those strings.
BinaryBuffer, PdfOperators, and most of the rest of NextPDF\Support\ are
internal infrastructure. The writer and drawing layers use them. This page
documents them for completeness and audit. They are not part of the supported
public application programming interface (API). Depend on the Document
façade and the Contracts namespace instead. SystemClock,
WarningCollector, Warning, WarningCode, WarningSeverity, and
DegradationImpact are public-facing members.
API surface
Section titled “API surface”| Symbol | Kind | Visibility | Key members |
|---|---|---|---|
NextPDF\Support\SystemClock | final class | public | now(): DateTimeImmutable (PSR-20 ClockInterface) |
NextPDF\Support\WarningCollector | final class | public | add(), emit(), addWithPolicy(), getWarnings(), hasWarnings(), hasDegradedParity(), clear() |
NextPDF\Support\Warning | final readonly class | public | $code, $severity, $page, $elementType, $featureId, $degradedParity, $message, $impact, $capabilityId |
NextPDF\Support\WarningCode | string enum | public | stable NEXTPDF_W_* identifiers |
NextPDF\Support\WarningSeverity | string enum | public | Warning, Degraded |
NextPDF\Support\DegradationImpact | string enum | public | Cosmetic, LayoutRisk, SemanticLoss, ComplianceRisk, Blocking |
NextPDF\Support\PdfStringEscaper | final readonly class | internal | escapeLiteral(), escapeName() (static) |
NextPDF\Support\BinaryBuffer | final class | internal | write(), writeStream(), replaceAt(), extract(), enableStreaming(), getContents() |
NextPDF\Support\PdfOperators | final class | internal | content-stream operator format-string constants |
Code sample — Quick start
Section titled “Code sample — Quick start”Read collected warnings after generation.
<?php
declare(strict_types=1);
use NextPDF\Support\WarningCollector;
$collector = new WarningCollector();
// The engine appends warnings during rendering. After generation:if ($collector->hasWarnings()) { foreach ($collector->getWarnings() as $warning) { \printf( "[%s] page %d: %s\n", $warning->code->value, $warning->page, $warning->message, ); }}Code sample — Production
Section titled “Code sample — Production”Inject a clock to make time deterministic, and treat a degraded-parity warning as a build failure.
<?php
declare(strict_types=1);
use NextPDF\Support\SystemClock;use NextPDF\Support\WarningCollector;use Psr\Clock\ClockInterface;
// Production uses the real system clock.$clock = new SystemClock();$now = $clock->now(); // DateTimeImmutable$epoch = $now->getTimestamp(); // int
// In tests, swap in any ClockInterface that returns a fixed instant// (the parameter is typed to the PSR-20 interface, not SystemClock).function buildReport(ClockInterface $clock): \DateTimeImmutable{ return $clock->now();}
$collector = new WarningCollector();// ... run generation ...if ($collector->hasDegradedParity()) { throw new \RuntimeException('Output parity degraded; failing the build.');}Edge cases & gotchas
Section titled “Edge cases & gotchas”SystemClock::now()returns a newDateTimeImmutableon each call. Do not assume two calls return the same instant. For fixed time, inject a frozen clock.WarningCollectoris in-memory and per-instance. It is the primary warning channel. The JavaScript Object Notation (JSON) sidecar and command-line interface (CLI) standard error (STDERR) output are emitted at the output boundary, not by the collector itself.addWithPolicy()can throwDegradedExceptionmid-render under a strict policy. Catch it at the generation boundary if you need partial output.WarningCodevalues are stable strings. Match on the enum case, not the message text, which is human-readable and may change.BinaryBuffer::getLength()is an intentional alias ofgetOffset()for stream-interface parity. Both return the same byte count.- Treat
PdfStringEscaper,BinaryBuffer, andPdfOperatorsas internal infrastructure. They are not covered by the public API stability promise.
Performance
Section titled “Performance”SystemClock::now() constructs one object and runs in O(1). WarningCollector
appends are amortized O(1) list pushes. getWarnings() returns the backing
list. In streaming mode, BinaryBuffer holds memory to its maxmemory
threshold (default 2 MB) before spilling to disk, which keeps peak memory flat
for large documents. The default performance_budget for this reference page
is wall_ms: 1500, peak_mb: 64.
Security notes
Section titled “Security notes”Use the clock surface to remove wall-clock nondeterminism from signed and
timestamped output by injecting a fixed clock alongside
Config::deterministic. PdfStringEscaper is the single auditable escaper for
PDF string and name output. Route all string emission through it to prevent
content injection through unescaped parentheses or delimiters in user-supplied
text. Warnings may carry document-derived details, such as element types and
feature ids. Scrub warning output before you forward it to a low-trust log
sink.
Conformance
Section titled “Conformance”| Spec | Clause | Topic |
|---|---|---|
| PSR-20 (PHP-FIG) | psr_20_clock#2.1 | Clock read operation returns an immutable date-time |
| ISO 32000-2:2020 | §7.3.4.2 / §7.3.5 | Literal-string and name-object escaping (paraphrased; ISO prose not quoted, no chunk pinned) |
SystemClock implements the PSR-20 ClockInterface. The escaper follows the
PDF literal-string and name-object character rules. The ISO text is paraphrased
under the site citation policy; no verbatim chunk is pinned.
See also
Section titled “See also”/modules/core/exception/—DegradedExceptionraised byaddWithPolicy()/modules/core/contracts/—DegradationPolicy,Capability/modules/core/observability/— warning forwarding and metrics/modules/core/config/—Config::deterministicpairs with the clock/modules/core/writer/— internal consumer ofBinaryBufferandPdfOperators
Glossary: PSR-20 · degradation policy · value object