跳到內容

從 TCPDF 6.x 遷移至 NextPDF

這項遷移遵循明確順序:先以最小幅度變更切換到 NextPDF 引擎;驗證已可運作的部分;稽核尚未運作的部分;逐一修正呼叫點;接著移除轉接層。相容性層支援第二到第四步,但它不是最終目的地。

本頁說明遷移策略。若要了解任一方法的確切行為,請搭配使用 /integrations/tcpdf-compat/method-coverage/ 與儲存庫內的權威對照表 docs/TCPDF_COVERAGE.md

TCPDF 6.x codebase

Swap dependency: install compat-legacy

Run existing suite unchanged

Strict-mode audit: enumerate behavioral gaps

Fix call sites: drop ignored params or move to modern API

Re-baseline byte-level test assertions

Remove the TCPDF dependency

Incrementally retire the adapter onto Document

Diagram

每個階段都會讓應用程式維持在可交付狀態。你永遠不需要一次完成整體切換。

安裝 nextpdf/compat-legacy(請參閱 /integrations/tcpdf-compat/install/)。請勿立即移除 tecnickcom/tcpdf——同時保留兩者可讓你進行比對。

選擇舊版呼叫點要如何解析該類別:

  • **建議做法:**逐檔將 use/require 改為 use NextPDF\Compat\Tcpdf\TCPDF;。這種做法明確,也可用 grep 搜尋。
  • **當你尚無法變更呼叫點時:**在啟動時以 LegacyBootstrap::enableAliases() 一次性啟用選用的全域別名(請參閱 /integrations/tcpdf-compat/boot-and-discovery/)。這會將 \TCPDF 以及四個輔助類別解析至轉接層。

這兩種策略在實務上互斥。如果真正的 TCPDF 函式庫仍可被自動載入,而你又啟用了全域別名, 則當 \TCPDF 類別已存在時,別名會被略過。你可能因此在無聲無息間持續使用舊版 TCPDF。在階段 1 期間,建議採用逐檔匯入,這樣你才能明確知道每個呼叫點使用的是哪個類別。請參閱 /integrations/tcpdf-compat/troubleshooting/.

階段 2 — 不變更地執行既有的測試套件

標題為「階段 2 — 不變更地執行既有的測試套件」的區段

在不做其他程式碼變更的情況下,針對轉接層執行完整測試套件。大多數委派方法(受測的約 120 個中有 94 個)行為都相容。請預期會出現兩類可預測的失敗:

  1. **位元組層級的斷言。**比對確切 PDF 位元組的測試會失敗,因為這個引擎是獨立實作。這是預期行為,並非缺陷。請將這些測試延後至階段 4 處理。
  2. **回傳值分支。**少數方法回傳的是相容性佔位值,而非計算後的數值;其中最值得注意的是 MultiCell() 回傳 1,而 Write() 回傳 0。依據這些回傳值進行分支判斷的程式碼需要調整。

為每一項失敗建立記錄。將每一項歸類為 位元組基準回傳值真正的行為落差

這個階段會讓遷移變得安全可控。啟用嚴格模式後,執行測試套件(或具代表性的正式環境路徑):

examples/migration-audit.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;
use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void
{
// ... your existing rendering code, unchanged ...
}
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->setStrictMode(true);
try {
renderInvoice($pdf);
$pdf->Output(__DIR__ . '/audit.pdf', 'F');
} catch (TcpdfNotImplementedException $e) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $e->getMessage() . "\n");
}

每個 TcpdfNotImplementedException 都是一項工作項目。訊息會包含方法名稱、確切被忽略的參數清單,以及一則遷移提示。會擲出例外的方法集合已列舉於 tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php,並有測試斷言涵蓋。每一項的原理說明則記載於 docs/TCPDF_COVERAGE.md

請將嚴格模式作為專屬的 CI 工作執行,而不要在正式環境中執行。它的目的在於揭露落差,不是讓正式環境擲出例外。

針對每項落差,選擇成本最低的正確修正方式:

落差樣態修正方式
被忽略的參數無關緊要(e.g. 你從未依賴的 TCPDF $align移除該參數。該呼叫就會完全相容。
被忽略的參數確有影響(e.g. 可點擊的 Image() 連結)透過現代化 API 重新表達。先繪製影像,再於該矩形範圍上加入 Document::link()
方法尚未實作(setSignature()endPage()endPage() / Open():移除該呼叫。簽署:請參閱 /integrations/tcpdf-compat/security-and-operations/——需要商用版本。
不適用的方法(setPDFVersion()setUserRights()移除。輸出一律為 PDF 2.0;user-rights 在 PDF 2.0 中已棄用。
回傳值分支自行計算該數值,或將該邏輯移轉至現代化 API。

對於任何 TCPDF 介面無法表達的項目,請使用這個逃生出口:

examples/migration-escape-hatch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
// Legacy path stays as-is for the parts that work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here:
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

用針對真正重要事項的斷言,取代確切位元組的斷言:

  • 輸出以 %PDF 開頭,且可被解析(冒煙測試層級)。
  • 已算繪的文字內容存在(擷取文字並對其斷言)。
  • 結構屬性(頁數、頁面大小、是否存在大綱)相符。

這是一次性成本,並能產生足以在未來引擎升級後仍有效的測試。

一旦嚴格模式稽核通過、正式環境的嚴格模式維持關閉,且測試套件在重新建立基準的斷言下皆為綠燈,即可移除 tecnickcom/tcpdf

Terminal window
composer remove tecnickcom/tcpdf

重新執行測試套件。若仍有任何項目解析至真正的 TCPDF 類別,代表階段 1 的別名注意事項生效了——請修正其餘呼叫點,明確匯入轉接層。

轉接層是遷移輔助工具,不是永久存在的層。在 TCPDF 已移除且引擎已完成驗證後,請漸進式淘汰轉接層:

  1. 在每個模組中,將 new TCPDF(...) 替換為現代化的 NextPDF\Core\Document 建構方式。
  2. 將 TCPDF 方法呼叫替換為其現代化的對應項目(你在階段 4 已加入的 getDocument() 呼叫就是範本)。
  3. 當某個模組不再參考轉接層時,刪除其相容性匯入。
  4. 當沒有任何模組參考轉接層時,將 nextpdf/compat-legacycomposer.json 中移除。

此時你便已在現代化的 PDF 2.0 API 之上運行,不再有相容性層。

  • 已安裝 nextpdf/compat-legacy;引擎連結已驗證。
  • 呼叫點明確匯入轉接層(或已啟用別名,並已將真正的 TCPDF 從自動載入路徑中移除)。
  • 已針對轉接層執行完整測試套件;失敗已分類。
  • 已加入嚴格模式 CI 工作;每項落差皆已建立記錄。
  • 每項落差皆已修正(移除參數/改用現代化 API/移除呼叫)。
  • 位元組層級的斷言已重新建立基準至 content/structure.
  • 已移除 tecnickcom/tcpdf;測試套件為綠燈。
  • 已逐模組淘汰轉接層;相依套件已移除。
  • /integrations/tcpdf-compat/method-coverage/ — 各方法行為與替換指引
  • docs/TCPDF_COVERAGE.md — 權威且經測試驗證的對照表
  • /integrations/tcpdf-compat/configuration/ — 將設定從全域常數中遷出
  • /integrations/tcpdf-compat/security-and-operations/ — 遷移期間的加密與簽署
  • /integrations/tcpdf-compat/troubleshooting/ — alias/real-TCPDF 衝突與其他陷阱