管線模型
Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 Evidence: Code-backed
一份 NextPDF 文件不是透過單一、不透明的步驟產生。它會流經少數幾個明確階段:記錄意圖的 facade、將意圖轉換成模型的內容層,以及把該模型序列化為合規 PDF 的 writer。本頁說明這個結構,以及它為何採取這樣的設計。
這為何重要
標題為「這為何重要」的區段PDF 檔案格式本身就是一個分層結構——一個檔頭、一段物件主體、一張交叉參照表,以及一個 trailer——而 writer 必須一致地組裝這一切。如果建構它的引擎是一段彼此糾纏的單一程序,那麼每一次變更都會危及每一份輸出。這樣一來,要建立信心的唯一辦法就是渲染整份文件並用肉眼檢視,而這既緩慢、又太晚,也缺乏說服力。
明確的管線翻轉了這個局面。每個階段只有一項職責與一道型別化的邊界,因此你可以針對一項變更推斷其影響,並在它所觸及的階段加以測試,而不必只在檔案的最終結果上測試。這套架構首先是一項關於可測試性與可擴充性的決策。
簡短版本
標題為「簡短版本」的區段- 公開的進入點是一個 Document facade。它是一個流暢、一次性使用、worker 安全的建構器,記錄的是你想要什麼,而非它如何被序列化。
- 這個 facade 會委派給大約二十多個各司其職的 concern trait(文字輸出、繪圖、頁面、安全性、導覽等等)——每一個只負責一項職責,而不是交給一個龐大的類別。
- 內容透過兩條路徑之一進入:直接繪圖(圖形基本元素)或 HTML/CSS 引擎。兩者都會產生相同的內部文件模型。
- 一個專責的 PDF writer 會序列化該模型,並選擇 PDF 1.4 / 1.7 / 2.0 的策略。有效的檔案結構只在這裡產生,別無他處。
- 長存的狀態(字型與影像登錄表)屬於行程範圍且為共用;每次請求的狀態(文件)則是全新建立、絕不重複使用。這道邊界是明確的,而這正是讓 worker 執行環境安全的原因。
NextPDF 如何處理這件事
標題為「NextPDF 如何處理這件事」的區段理解這個模型最清楚的方式,就是跟著一份文件從呼叫一路走到位元組。
- Document facade Fluent, use-once builder; records intent via concern traits.
- Content production Direct drawing or the HTML/CSS engine — both build one document model.
- Document model Accumulated pages, content, and resources held as typed state.
- PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
- Conforming PDF Header, object body, cross-reference table, trailer.
有兩項設計抉擇,讓這不只是一張圖。
這個 facade 是組合而成的,而非單體式的。 Document 並非自己實作每一項功能;它把每個領域委派給一個專責的 concern trait——文字輸出、繪圖、頁面、安全性、字體排印、導覽、交易等等。新的文件方法應該歸到擁有該領域的 trait,而不是放在 facade 本身上。你所呼叫的那個類別保持精簡,各項職責也保持彼此分離。
writer 是檔案結構的唯一擁有者。 內容產製決定存在哪些標記與物件;writer 則決定它們如何變成一個有效的 PDF 檔案,包括適用哪一種版本策略。這項分離由架構規則強制執行:版面配置與內容程式碼不會發出最終的檔案結構,而 writer 也不做版面配置決策。好處在於:「輸出是否是有效的 PDF?」這個問題恰好只有一個地方需要被測試。
生命週期邊界是這個模型的一部分,而不是事後才補上的。字型與影像登錄表存活於整個行程生命週期中,並在多個請求間共用;文件、其渲染情境,以及 writer 則是每次請求各自建立並於用後釋放。在 worker 執行環境中,這項區別正是安全重用與跨請求污染之間的分界。正因如此,這一點明訂於架構之中,而非仰賴自律。
證據怎麼說
標題為「證據怎麼說」的區段本頁為 Evidence: Code-backed 。這些階段對應到 core 儲存庫中的實際結構:
- facade 及其委派對應到
src/Core/Document.php,再加上src/Core/Concerns/中的 concern trait(文字輸出、輸出、繪圖、頁面、安全性、字體排印、導覽、交易等等——每一個各負責一項職責)。 - 這兩條內容路徑是 HTML/CSS 引擎(
src/Html/)與直接繪圖(src/Graphics/),兩者都將資料送入內部模型。 - 序列化與 PDF 版本策略位於
src/Writer/(PdfWriter.php,搭配明確的 PDF 1.4 / 1.7 / 2.0 策略類別)。 - 行程生命週期與每次請求之間的邊界,就是架構總覽中記載、並由隨附的 worker-factory 範例實際演練的 worker 安全設計;該範例在多個請求間共用同一個
FontRegistry與ImageRegistry,同時為每次請求各自全新建立一個Document。
目的地由格式決定。writer 的輸出必須具備一個檔頭、一段物件主體、一張交叉參照表,以及一個 trailer, Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 。將這項義務集中在單一階段,正是讓引擎的其餘部分得以持續專注於內容,而不是組裝檔案結構的原因。
實際範例
標題為「實際範例」的區段facade 的工作,是讓意圖本身讀起來就很清楚。對呼叫端而言,內容路徑與 writer 會保持隱形:
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone(); // facade$doc->setTitle('Quarterly Report'); // metadata concern$doc->addPage(); // pages concern$doc->setFont('helvetica', 'B', 16); // typography concern$doc->cell(0, 12, 'Summary', newLine: true); // text-output concern$doc->writeHtml('<p>Generated in-process.</p>'); // HTML content path$doc->save(__DIR__ . '/report.pdf'); // writer stage每一次呼叫都落在不同的 concern 中。兩條不同的內容路徑都送入同一個模型。恰好只有一個階段——save()——會把模型轉成檔案位元組。呼叫端不需要知道交叉參照表是如何建構的。
常見誤解
標題為「常見誤解」的區段常見的誤讀是以為「管線」意味著一個串流式的 push API,需要你把一個階段接到下一個階段,就像 Unix pipe 那樣。它並非如此。這裡的管線是一種架構性的拆解:各個階段具有單一職責與型別化的邊界。你仍然是在使用流暢的 facade 開發。這些階段是建構與測試引擎的方式,而不是一條需要你手動組裝的傳輸通道。
另一個相關誤解,是假設 facade 就是引擎。它是進入點。真正的工作分散在 concern trait、兩條內容路徑,以及一個 writer 之間。正是這種分散,使得一項功能變更不會危及每一份輸出。
限制與邊界
標題為「限制與邊界」的區段本頁描述的是這條管線的結構,而非任何單一階段的內部 API。確切的 concern-trait 清單、writer 策略選擇規則,以及內容模型欄位,是由程式碼與參考文件所定義,而非由本說明所定義。確切的 trait 數量是一項實作細節,可以在不改變模型的前提下變動。本頁不涵蓋 HTML 引擎的內部階段(屬於另一主題),也不涵蓋 writer 的串流與記憶體行為(同樣另成一篇)。這些結構性陳述截至本頁審閱日期為止是準確的;權威來源是 core 儲存庫的 src/Core/、src/Html/、src/Graphics/,以及 src/Writer/。
管線模型在各版本之間完全相同;各版本是在既有階段內增添能力,而非新增階段:
| Edition | Availability |
|---|---|
| Core | Core 實作完整的 facade → 內容 → writer 管線。 |
| Pro | Pro 在既有階段內增添能力,而非新增階段。 |
| Enterprise | Enterprise 在既有階段內增添能力,而非新增階段。 |
相關文件
標題為「相關文件」的區段詞彙表
標題為「詞彙表」的區段- Facade——公開的
Document進入點:一個流暢、一次性使用的建構器,記錄意圖並委派給 concern trait。 - Concern trait——facade 所組合、各司其職的 PHP trait,每一個都擁有單一功能領域(文字輸出、繪圖、頁面、安全性等等)。
- Content path——內容進入模型的兩種方式之一:直接繪圖或 HTML/CSS 引擎。
- Document model——引擎在序列化之前,對頁面、內容與資源所累積的內部型別化狀態。
- Writer stage——將模型序列化為有效 PDF 的元件,並選擇 PDF 1.4 / 1.7 / 2.0 的策略。
- Worker-safe——其設計讓行程生命週期狀態得以安全共用,而每次請求的狀態則是全新建立、絕不重複使用。