NextPDF compat-legacy 的引导与发现
nextpdf/compat-legacy 提供一个 TCPDF 兼容门面——类 NextPDF\Compat\Tcpdf\TCPDF——并将操作委托给 NextPDF 引擎。它是一个兼容层,并不是可直接替换的克隆实现。在已调研的约 120 个 TCPDF 6.x 方法中,它通过直接委托覆盖了 94 个。其余方法存在已记录的行为差异(参见 /integrations/tcpdf-compat/method-coverage/)。
它不会在自动加载时进行全局接线。默认情况下,引入该包并不会创建全局的 \TCPDF 类。你需要显式选择启用全局别名,或者采用迁移期间推荐的方式:在每个文件中导入适配器类。
TCPDF 门面如何暴露
标题为“TCPDF 门面如何暴露”的章节该门面是一个普通的 PSR-4 自动加载类:
| 项目 | 值 |
|---|---|
| 门面类 | NextPDF\Compat\Tcpdf\TCPDF |
| PSR-4 前缀 | NextPDF\Compat\Tcpdf\ 映射到 src/Compat/Tcpdf/ |
| 共享契约 | NextPDF\Compat\Contracts\CompatAdapterInterface |
| 逃生口 | TCPDF::getDocument() 返回被包装的 NextPDF\Core\Document |
该类有意不是 final 的:旧版 TCPDF 用户通常会子类化 TCPDF 来覆盖 Header() 和 Footer(),因此适配器保留了这个扩展点。在内部,该类是一个门面。它组合了 25 个按单一职责拆分的关注点 trait,并将所有 PDF 操作委托给构造时创建的 Document 实例。
引导序列
标题为“引导序列”的章节构造是唯一的“引导”步骤。包本身没有服务容器注册,也没有框架引导。框架集成需要由你自行添加一层很薄的封装——参见 /integrations/tcpdf-compat/integration/.
LegacyDefaults::register() 是幂等的:它仅在某个常量尚未定义时才定义该常量。只要在首次构造之前定义,应用自定义的常量始终优先(参见 /integrations/tcpdf-compat/configuration/ § 配置解析顺序)。
可选启用的全局类别名
标题为“可选启用的全局类别名”的章节如果你的代码库通过全局命名空间调用 new \TCPDF(...),而你暂时无法修改这些调用点,可以在应用引导时一次性注册全局别名:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Global names now resolve to the adapter:$pdf = new \TCPDF('P', 'mm', 'A4');enableAliases() 会注册 \TCPDF、\TCPDF_STATIC、\TCPDF_FONTS、\TCPDF_COLORS 以及 \TCPDF_IMAGES。它的行为(由 tests/Unit/Compat/Tcpdf/LegacyBootstrapTest.php 断言)如下:
- 它是幂等的——调用两次不会抛出异常,且只注册一次。
LegacyBootstrap::isRegistered()会报告它是否已运行。- 注册之后,
new \TCPDF()是适配器的一个实例。
避免与真实 TCPDF 安装产生冲突
标题为“避免与真实 TCPDF 安装产生冲突”的章节这是本页面最重要的一条规则。
enableAliases() 仅在不存在同名类时才注册别名(class_exists($alias, autoload: false))。因此:
- 如果已安装
tecnickcom/tcpdf,并且其\TCPDF先被加载,别名会被静默跳过,你的代码将继续使用旧版 TCPDF,而不是适配器。 - 不支持在同一进程中同时运行两个库并启用全局别名;这样会导致行为不确定。
迁移期间,优先使用显式的逐文件导入(use NextPDF\Compat\Tcpdf\TCPDF;)。它们可以用 grep 检索,也不会产生歧义。一旦严格模式审计通过,就移除 tecnickcom/tcpdf(参见 /integrations/tcpdf-compat/migration/ 阶段 5)。当 \TCPDF 解析为错误的类时,/integrations/tcpdf-compat/troubleshooting/ 中有相应的诊断方法。
容器绑定
标题为“容器绑定”的章节该包不附带任何框架容器绑定。如果你要在容器中绑定该门面,请绑定一个工厂,让它为每个文档返回一个全新的 NextPDF\Compat\Tcpdf\TCPDF。文档状态按实例隔离,不得在彼此无关的文档之间共享(参见 /integrations/tcpdf-compat/production-usage/ § 并发)。/integrations/tcpdf-compat/integration/. 中展示了一个典型的绑定。
配置解析顺序
标题为“配置解析顺序”的章节构造时,适配器按以下顺序解析配置:首先是构造函数参数,其次是任何已存在且由应用自定义的旧版常量,最后是 LegacyDefaults 的 TCPDF 6.2.13 默认值(用于任何尚未定义的常量)。有关完整细节以及现代化的 AdaptationConfig 对象,参见 /integrations/tcpdf-compat/configuration/.
要确认门面已接线且引擎链接已解析,请构造一个适配器并生成一个单页 PDF,然后检查 %PDF 前缀。这与包输出测试断言的是同一行为表面。可运行的检查见 /integrations/tcpdf-compat/install/ § 验证安装。
要在启用别名之前检测真实 TCPDF 冲突,请在你将要调用 enableAliases() 的位置,检查是否已存在全局 \TCPDF。如果存在,某个别名将被跳过,因此请在依赖适配器之前解决冲突(使用显式导入,或移除真实的 TCPDF)。
TCPDF API 覆盖范围
标题为“TCPDF API 覆盖范围”的章节权威且经过测试验证的覆盖矩阵是仓库内文件 docs/TCPDF_COVERAGE.md。面向读者的摘要(包括静默忽略和未实现方法列表)是 /integrations/tcpdf-compat/method-coverage/. 该包并不宣称自己是“可直接替换的替代品”或“100% TCPDF 兼容”;它是一个 TCPDF 兼容的替代方案,具有已知且经过测试验证的兼容表面,以及已记录的行为差异。
另请参见
标题为“另请参见”的章节docs/TCPDF_COVERAGE.md—— 权威覆盖信息来源(仓库内)- /integrations/tcpdf-compat/integration/ —— 将门面接入 application/framework
- /integrations/tcpdf-compat/method-coverage/ —— 各方法的行为与差距
- /integrations/tcpdf-compat/migration/ —— 分阶段迁移策略
- /integrations/tcpdf-compat/troubleshooting/ —— alias/real-TCPDF 冲突诊断
tests/Unit/Compat/Tcpdf/LegacyBootstrapTest.php—— 别名行为判定基准