跳转到内容

NextPDF Laravel 启动与自动探索

Laravel 会根据包自身的 composer.json 自动探索 NextPdfServiceProvider。这个 provider 会注册延迟(deferred)的容器绑定,并在 console(控制台)上下文中发布配置文件。本页逐一说明自动探索机制与每个绑定的生命周期。

Terminal window
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

包会在自身 composer.jsonextra.laravel 块中声明 provider 与 facade 别名:

resource: composer.json (extra.laravel)
{
"extra": {
"laravel": {
"providers": [
"NextPDF\\Laravel\\NextPdfServiceProvider"
],
"aliases": {
"Pdf": "NextPDF\\Laravel\\Facades\\Pdf"
}
}
}
}

当你运行 composer require 时,Laravel 会读取这个块并注册 provider 与别名。你不需要手动编辑 config/app.phpbootstrap/providers.phpextra.laravel.providers 数组会自动注册 provider,而 extra.laravel.aliases 会自动注册 facade 别名(Laravel 12 包开发指南, https://laravel.com/docs/12.x/packages,访问日期 2026-05-18)。

NextPdfServiceProvider 同时实现 DeferrableProvider 和标准的 register() / boot() 生命周期。

  1. register() 会把包配置合并到 nextpdf 键之下。接着它会绑定容器条目:字体注册表、图像注册表、文档工厂、PSR-18 HTTP 客户端、timestamp 客户端、签章器、文档,以及 e-invoice 合约。每个绑定都是闭包,因此这里不会构造任何重量级对象。
  2. boot() 会检查 mbstringzlib 这两个 PHP 扩展是否已加载。它只会在 nextpdf-config 标签下注册可发布的配置,且仅当 runningInConsole() 为 true 时。

这个 provider 是延迟加载的,因此只有当你 resolve(解析)provides() 返回的某个条目时,register() 才会运行。解析其他无关的容器键不会启动 NextPDF。

PSR-11 允许用相同标识符连续调用两次 get(),并按绑定策略返回不同的值(PSR-11 §1.1.2)。这个 provider 有意依赖这一特性:

绑定键生命周期备注
FontRegistryInterface(含 FontRegistry 别名)单例(singleton),预热后锁定preload_fonts 预热;锁定后任何请求都无法更改它
ImageRegistry单例(singleton)image_cache_mb 决定容量的有界 LRU 缓存;不锁定
DocumentFactoryInterface(含 DocumentFactory 别名)单例(singleton)无状态;共享前述两个注册表
Psr\Http\Client\ClientInterface单例(singleton)带请求伪造防护的客户端,封装一个 curl 客户端;由 tsa.* 构造
TsaClient作用域(scoped)null(当 tsa.url 为空时)
SignerInterface工厂(factory)null(当签章停用或凭证为空时)
PdfDocumentInterface(含 nextpdf 别名)工厂(factory)每次解析都会生成全新的 NextPDF\Core\Document,并应用默认元数据
EmbedderInterfaceValidatorInterfaceProfileInterfaceSchematronRunnerInterface工厂(factory)解析为 Premium 具体实现;首次解析时,如果缺少该包就会报错:nextpdf/premium

文档绑定会把 defaults.creatordefaults.language,以及(非空时)defaults.author 应用到每份新建文档。当 pdfa 不为 null 时,它会启用 PDF/A(Premium)。当存在 artisan 区段且有 Chrome 浏览器工厂类时,它会应用 Chrome renderer(渲染器)配置。

has() 在容器中接受单一字符串标识符(PSR-11 §1.1.2)。e-invoice 合约已被绑定,因此即使缺少 Premium,has() 对它们仍返回 true。缺少的具体实现只会在构造时出错。

把包加入应用的 dont-discover 数组,然后手动注册 provider:

resource: application composer.json
{
"extra": {
"laravel": {
"dont-discover": ["nextpdf/laravel"]
}
}
}
resource: bootstrap/providers.php
<?php
declare(strict_types=1);
return [
App\Providers\AppServiceProvider::class,
NextPDF\Laravel\NextPdfServiceProvider::class,
];

每个键按以下顺序解析:环境变量 → 已发布的 config/nextpdf.php 值 → 在 register() 中合并的包默认值。大多数键可接受 NEXTPDF_* 名称或旧版 TCPDF_* 环境变量名称。建议优先使用 NEXTPDF_*

Terminal window
php artisan package:discover --ansi

输出中出现列出 nextpdf/laravel 的一行,即可确认自动探索成功。由于 provider 是延迟加载的,绑定本身要等到第一次解析后才会出现。这行探索消息才是正确的成功信号。

  • 配置发布只会在 console 上下文中注册,因此纯 Web 请求永远不会触发它。请从 CLI 运行 vendor:publish
  • 除了注册表、工厂、HTTP 客户端、签章器、timestamp 与文档等键之外,provides() 还包含四个 e-invoice 合约键。
  • 全新安装在第一次相关解析之前,看起来可能像是没有生效。这是延迟 provider 的设计,并不是错误。

register() 是 O(1),只包含闭包。字体注册表预热的复杂度是预载字体数的 O(f),且每个 worker 进程只运行一次。延迟加载 provider 可以避免 NextPDF 的构造成本进入框架启动路径,直到实际用到某个绑定为止。

延迟设计缩小了启动时的攻击面。锁定的字体注册表可以防止长生命周期 worker 中出现跨请求的字体状态变更。如需完整的威胁覆盖说明,请见 /integrations/laravel/security-and-operations/。

主张来源条款参考 ID(reference_id)
连续解析可能会因绑定策略而不同PSR-11 容器(Container)§1.1.2
has() 接受单一字符串标识符PSR-11 容器(Container)§1.1.2

Laravel 探索键名已对照官方 Laravel 12 包文档查证(https://laravel.com/docs/12.x/packages,访问日期 2026-05-18)。

Premium 具体实现会通过相同的延迟绑定键来解析。这是可选的 Enterprise 能力;本页所述的 Core 包无需修改任何代码即可采用它。请见 https://nextpdf.dev/get-license/?intent=laravel-signing

  • /integrations/laravel/install/ — 安装与发布
  • /integrations/laravel/overview/ — 包架构
  • /integrations/laravel/integration/ — 端到端接入教程
  • /integrations/laravel/configuration/ — 所有配置键