Support:共用工具 + Clock + Sleeper
Support 模組存放引擎內部使用的橫切工具。它也提供一小部分對外介面:PSR-20 system clock、warning 收集流程,以及 PDF 序列化 primitives。此命名空間大多屬於內部基礎設施。本頁記錄外部呼叫端可以依賴的部分,並標示僅供內部使用的部分。
composer require nextpdf/core:^3概念說明
標題為「概念說明」的區段Clock(PSR-20)。 SystemClock 實作 Psr\Clock\ClockInterface。它的 now() 會以 DateTimeImmutable 形式回傳目前時間。PSR-20 模型定義的是一個只有讀取操作的 clock 介面。該操作會以不可變的 date-time 值回傳目前時間(PSR-20 psr_20_clock#2.1)。SystemClock 是預設值;沒有注入任何 clock 時,引擎就會使用它。在測試中若要固定時間,請改為注入 frozen clock。它必須實作相同的介面。將 clock 搭配 Config::deterministic,即可得到完全相同的輸出。
Warning 流程。 WarningCollector 是非致命渲染問題的主要記憶體內傳遞通道。每次發生確定性降級時,引擎都會附加一筆 Warning,例如表格欄位被擠壓、font 無法 resolve(解析),或缺少 glyph。呼叫端會在產生完成後透過 Document::getWarnings() 讀取這些 warning。Warning 是不可變的 value object,包含一個 WarningCode、一個 WarningSeverity(warning 或 degraded)、頁碼、元素型別、feature id、降級對等旗標、訊息、一個 DegradationImpact,以及一個選用的 capability id。WarningCode 是以字串為底、由穩定識別碼組成的 enum。它們以 NEXTPDF_W_ 為前綴(例如 NEXTPDF_W_FONT_UNRESOLVED)。這個前綴讓它們在測試中可以安全地比對。addWithPolicy() 會強制套用目前生效的 DegradationPolicy。在 strict 政策下,compliance、semantic 或 blocking 影響會擲出 DegradedException。在 balanced 政策下,只有 blocking 影響會擲出例外。permissive 政策永遠不會擲出例外。
PDF primitives。 PdfStringEscaper 是 PDF 字串與 name 跳脫的單一事實來源。escapeLiteral() 會跳脫 PDF 字面字串所需的字元(反斜線、括號、CR、LF、HT、BS、FF),並移除 NUL。escapeName() 會把可列印 ASCII 範圍以外的位元組,以及 PDF 分隔字元集合,以十六進位編碼成 name 物件。BinaryBuffer 是針對寫入最佳化的二進位累積器,用來建構 PDF 物件與 stream。在 streaming 模式下,它會把大型文件溢出到 php://temp 控制代碼。它也支援 signature 嵌入所需的 byte-range 操作。PdfOperators 存放 content-stream 運算子的格式字串(path、text、graphics-state、font),由 drawing 層與 parser 層共用。
BinaryBuffer、PdfOperators,以及 NextPDF\Support\ 中其餘大部分,都屬於 內部基礎設施。writer 層與 drawing 層會使用它們。在此記錄它們,是為了完整性與稽核。它們並非受支援的公開 API。請改為依賴 Document 門面與 Contracts 命名空間。SystemClock、WarningCollector、Warning、WarningCode、WarningSeverity,以及 DegradationImpact 才是對外公開的成員。
API 介面
標題為「API 介面」的區段| 符號 | 種類 | 可見性 | 主要成員 |
|---|---|---|---|
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 | 穩定的 NEXTPDF_W_* 識別碼 |
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 | 內部 | escapeLiteral()、escapeName()(static) |
NextPDF\Support\BinaryBuffer | final class | 內部 | write()、writeStream()、replaceAt()、extract()、enableStreaming()、getContents() |
NextPDF\Support\PdfOperators | final class | 內部 | content-stream 運算子格式字串常數 |
程式碼範例 — 快速上手
標題為「程式碼範例 — 快速上手」的區段產生完成後,讀取收集到的 warning。
<?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, ); }}程式碼範例 — 正式環境
標題為「程式碼範例 — 正式環境」的區段注入 clock 以取得確定性時間,並將降級對等 warning 視為建置失敗。
<?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()每次呼叫都會回傳一個新的DateTimeImmutable。不要假設兩次呼叫會回傳相同的時刻。若要固定時間,請注入 frozen clock。WarningCollector存放於記憶體中,且每個實例彼此獨立。它是主要通道。JSON sidecar 與 CLI STDERR 是在輸出邊界發出,而非由 collector 本身發出。addWithPolicy()在 strict 政策下可能於渲染中途擲出DegradedException。若你想要部分輸出,請在產生流程邊界處攔截它。WarningCode的值是穩定字串——請比對 enum case,而非訊息文字;訊息文字是給人讀的,可能會變動。BinaryBuffer::getLength()是getOffset()有意提供的別名,用於與 stream 介面對齊。兩者回傳相同的位元組計數。- 請將
PdfStringEscaper、BinaryBuffer,以及PdfOperators都視為內部使用。它們不在公開 API 穩定性承諾的涵蓋範圍內。
SystemClock::now() 是一次物件建構,O(1)。WarningCollector 的附加是攤提 O(1) 的 list push。getWarnings() 回傳底層的 list。BinaryBuffer 在 streaming 模式下,會先將記憶體使用量維持在其 maxmemory 門檻(預設 2 MB)以下,超過後才溢出到磁碟,讓大型文件的尖峰記憶體保持平穩。本參考頁的預設 performance_budget 為 wall_ms: 1500、peak_mb: 64。
安全注意事項
標題為「安全注意事項」的區段clock 介面讓你能搭配 Config::deterministic 注入固定的 clock,從而移除已簽章與已加時戳輸出中由牆鐘時間造成的非確定性。PdfStringEscaper 是 PDF 字串與 name 輸出的唯一可稽核跳脫器。讓所有字串輸出都經過它,可防止使用者提供的文字因包含未跳脫的括號或分隔字元而造成內容注入。warning 可能帶有衍生自文件的細節(元素型別、feature id)。在把 warning 輸出轉送到低信任的 log sink 之前,請先加以清理。
符合性
標題為「符合性」的區段| 規格 | 條款 | 主題 |
|---|---|---|
| PSR-20(PHP-FIG) | psr_20_clock#2.1 | clock 讀取操作會回傳一個不可變的 date-time |
| ISO 32000-2:2020 | §7.3.4.2 / §7.3.5 | 字面字串與 name 物件的跳脫(為改寫版;未引用 ISO 原文,未釘選任何 chunk) |
SystemClock 實作 PSR-20 ClockInterface。此跳脫器遵循 PDF 字面字串與 name 物件的字元規則。ISO 文字依本站引用政策採改寫版,且未釘選任何 verbatim chunk。
另請參閱
標題為「另請參閱」的區段/modules/core/exception/—— 擲出DegradedException的addWithPolicy()/modules/core/contracts/——DegradationPolicy、Capability/modules/core/observability/—— warning 轉送與 metrics/modules/core/config/——Config::deterministic與 clock 搭配使用/modules/core/writer/—— 內部使用的BinaryBuffer與PdfOperators
術語表:PSR-20 · 降級政策 · value object