Skip to content

Support: shared utilities + Clock + Sleeper

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.

Terminal window
composer require nextpdf/core:^3

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.

SymbolKindVisibilityKey members
NextPDF\Support\SystemClockfinal classpublicnow(): DateTimeImmutable (PSR-20 ClockInterface)
NextPDF\Support\WarningCollectorfinal classpublicadd(), emit(), addWithPolicy(), getWarnings(), hasWarnings(), hasDegradedParity(), clear()
NextPDF\Support\Warningfinal readonly classpublic$code, $severity, $page, $elementType, $featureId, $degradedParity, $message, $impact, $capabilityId
NextPDF\Support\WarningCodestring enumpublicstable NEXTPDF_W_* identifiers
NextPDF\Support\WarningSeveritystring enumpublicWarning, Degraded
NextPDF\Support\DegradationImpactstring enumpublicCosmetic, LayoutRisk, SemanticLoss, ComplianceRisk, Blocking
NextPDF\Support\PdfStringEscaperfinal readonly classinternalescapeLiteral(), escapeName() (static)
NextPDF\Support\BinaryBufferfinal classinternalwrite(), writeStream(), replaceAt(), extract(), enableStreaming(), getContents()
NextPDF\Support\PdfOperatorsfinal classinternalcontent-stream operator format-string constants

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,
);
}
}

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.');
}
  • SystemClock::now() returns a new DateTimeImmutable on each call. Do not assume two calls return the same instant. For fixed time, inject a frozen clock.
  • WarningCollector is 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 throw DegradedException mid-render under a strict policy. Catch it at the generation boundary if you need partial output.
  • WarningCode values 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 of getOffset() for stream-interface parity. Both return the same byte count.
  • Treat PdfStringEscaper, BinaryBuffer, and PdfOperators as internal infrastructure. They are not covered by the public API stability promise.

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.

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.

SpecClauseTopic
PSR-20 (PHP-FIG)psr_20_clock#2.1Clock read operation returns an immutable date-time
ISO 32000-2:2020§7.3.4.2 / §7.3.5Literal-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.

  • /modules/core/exception/DegradedException raised by addWithPolicy()
  • /modules/core/contracts/DegradationPolicy, Capability
  • /modules/core/observability/ — warning forwarding and metrics
  • /modules/core/config/Config::deterministic pairs with the clock
  • /modules/core/writer/ — internal consumer of BinaryBuffer and PdfOperators

Glossary: PSR-20 · degradation policy · value object