跳转到内容

Config:不可变文档配置

Config 是不可变的文档配置对象。每次更改设置,都会通过类型化 wither 返回一个新实例,因此该配置可以安全地在多个文档和工作进程之间共享。NextPdfConfig 是一个独立的静态类,用于保存进程级 CSS 解析器安全限制。

Terminal window
composer require nextpdf/core:^3

这两个类都随核心包一起提供。Config 自 1.7.0 起可用。NextPdfConfig 自 2.2.0 起可用。

Config 是一个 final readonly 类,并标记了 #[DisallowDynamicProperties]。它只保存标量和 final readonly 值对象,因此整个对象图都是深度不可变的。它不提供通用的 with(string, mixed) setter。每项变更都有专属的类型化 wither。共有 19 个——从 withPageSize()withMargins()withCompress() 一直到 withOutputColorProfile()——每一个都使用命名参数重新构造对象。采用命名参数重新构造是有意为之的:添加构造函数参数绝不会悄悄移动某个现有 wither 中的位置参数。一项兼容性测试会通过反射固定公共方法列表和参数数量;签名一旦漂移,CI 就会失败。

构造函数以安全的默认值公开完整配置面:

参数类型默认值
pageSizePageSizePageSize(595.276, 841.890, 'A4')
marginsMarginMargin(10.0, 10.0, 10.0, 10.0)
compressbooltrue
autoPageBreakbooltrue
breakMarginfloat20.0
langstring(BCP-47)''
fontsDirectorystring''
imageCacheBytesint52_428_800
deterministic?DeterministicSettingsnull
cryptoPolicy?CryptoPolicyInterfacenull
branding?BrandingConfignull
degradationPolicyDegradationPolicyBalanced
degradationOverridesarray<string, DegradationPolicy>[]
cssRenderingModeCssRenderingModeNormal
auditCollector?AuditCollectornull
cssFeatureFlags?CssFeatureFlagsnull
cssLayoutModeCssLayoutModeStreaming
retainedNodeBudgetint50_000
layoutTelemetryCollector?LayoutTelemetryCollectornull
telemetryEnabledboolfalse
outputColorProfileOutputColorProfileDeviceRGB

有三项设置带有取值范围。retainedNodeBudget 接受闭区间 [5_000, 100_000](常量 RETAINED_NODE_BUDGET_MINRETAINED_NODE_BUDGET_MAX,默认值 RETAINED_NODE_BUDGET_DEFAULT)。超出该范围时,withRetainedNodeBudget() 会抛出 InvalidArgumentException。在流式模式下,effectiveRetainedNodeBudget() 返回 0。否则它会将取值钳制回范围之内,作为针对直接按位置参数构造的纵深防御检查。validate() 强制执行单字段 wither 无法单独发现的跨字段不变式。CssLayoutMode::Auto 是保留值,会引发 NotImplementedExceptionCssRenderingMode::SafeCssLayoutMode::Retained 组合使用时会引发 IncompatibleRenderingModeExceptionauditCollector 是调用方提供的审计报告收集器。仅当 cssRenderingModeCssRenderingMode::Audit 时才会用到它,此时它会驱动一个私有的 nextpdfAudit XMP 块;在其他渲染模式下,它会被忽略。

NextPdfConfig 处理另一类关注点。它是一个不可实例化的静态工具类,用于保存进程级 CSS 解析器限制。这些限制包括样式表的最大字节数(默认 512 KB)和 CSS 最大嵌套深度(默认 8)。它们是防止恶意输入耗尽资源的安全边界,而不是单个文档的偏好设置。正因如此,它们才是静态的。setter 会将取值钳制到一个下限(字节数 max(1024, …),深度 max(1, …))。resetDefaults() 被标记为 @internal,仅供测试使用。

符号种类关键成员
NextPDF\Core\Configfinal readonly 类21 个构造函数参数;19 个类型化 wither;validate()isSafeMode()isRetainedMode()effectiveRetainedNodeBudget()resolveFeatureFlags()
NextPDF\Core\Config::RETAINED_NODE_BUDGET_MINconst int5_000
NextPDF\Core\Config::RETAINED_NODE_BUDGET_MAXconst int100_000
NextPDF\Core\Config::RETAINED_NODE_BUDGET_DEFAULTconst int50_000
NextPDF\Core\NextPdfConfigfinal 类setMaxCssBytes()getMaxCssBytes()setMaxCssNestingDepth()getMaxCssNestingDepth()resetDefaults()(@internal)

Wither 方法:withPageSizewithMarginswithCompresswithAutoPageBreakwithLangwithFontsDirectorywithImageCacheByteswithDeterministicwithCryptoPolicywithBrandingwithDegradationPolicywithDegradationOverridewithCssRenderingModewithCssFeatureFlagswithCssLayoutModewithRetainedNodeBudgetwithLayoutTelemetryCollectorwithTelemetryEnabledwithOutputColorProfile

从默认值构建配置,并调整其中的两项设置。

<?php
declare(strict_types=1);
use NextPDF\Core\Config;
use NextPDF\ValueObjects\Margin;
use NextPDF\ValueObjects\PageSize;
$config = (new Config())
->withPageSize(PageSize::Letter())
->withMargins(Margin::uniform(18.0));
// Each wither returns a new instance; the original is unchanged.

组合一个确定性的、经过校验的配置,并针对不受信任的输入收紧进程级 CSS 限制。

<?php
declare(strict_types=1);
use NextPDF\Core\Config;
use NextPDF\Core\CssRenderingMode;
use NextPDF\Core\NextPdfConfig;
use NextPDF\ValueObjects\Margin;
use NextPDF\ValueObjects\PageSize;
$config = (new Config())
->withPageSize(PageSize::A4())
->withMargins(Margin::symmetric(vertical: 20.0, horizontal: 15.0))
->withCompress(true)
->withCssRenderingMode(CssRenderingMode::Safe);
// Reject mutually exclusive modes before generation starts.
$config->validate();
// Process-wide hardening for hostile stylesheet input.
NextPdfConfig::setMaxCssBytes(262_144); // 256 KB
NextPdfConfig::setMaxCssNestingDepth(4);
  • Config 在你调用 validate() 之前不会应用任何跨字段规则。wither 无法单独检测出 Safe + Retained 冲突;请在生成之前调用 validate()
  • withRetainedNodeBudget() 是唯一一个会因自身输入而抛出异常的 wither(当取值在 [5_000, 100_000] 之外时,抛出 InvalidArgumentException)。
  • effectiveRetainedNodeBudget() 在流式模式下返回 0,表示“第一层预算不适用”,而不是“不允许任何节点”。
  • withLayoutTelemetryCollector()withTelemetryEnabled() 相互独立。接入一个收集器却不启用遥测,会将其暂存,以备后续金丝雀场景使用。启用遥测但不提供收集器是有效的,且为空操作。
  • NextPdfConfig 是进程级且静态的。一次更改会影响进程内的每个文档,直到被重置。它是一个安全边界,而不是单个文档的偏好设置。请勿将它放入每个请求的变更路径中。
  • NextPdfConfig::resetDefaults()@internal。请勿在生产代码中调用它。

一次 wither 调用会分配一个新的 Config,并复制对现有值对象的引用。相对于设置数量,这是 O(1) 的;它不会执行任何深拷贝,因为持有的每个值本身都是不可变的。NextPdfConfig 访问器读取静态字段,为 O(1)。本参考页的默认 performance_budgetwall_ms: 1500peak_mb: 64

NextPdfConfig 用于限定解析器的资源使用。默认的 512 KB 样式表上限和深度为 8 的嵌套上限,可防范由异常庞大或深度嵌套的 CSS 引发的拒绝服务。当样式表来源不受信任时,请同时调低这两项限制。Config::cryptoPolicy 携带用于强制执行加密策略的 CryptoPolicyInterface(例如 FIPS 配置)。它默认为 null,通过 withCryptoPolicy() 设置。Config::deterministic 用于控制固定的时间戳和标识符,以实现逐字节一致的输出,是可复现构建所必需的。

本模块属于引擎配置,没有任何规范性标准引用。那些驱动标准行为的设置——outputColorProfile(OutputIntent 发射)、cryptoPolicy(FIPS)、deterministic(可复现构建)——都在实际发射它们的模块中,对照各自的条款进行了说明。

  • /modules/core/document/ —— 使用 Config
  • /modules/core/valueobjects/ —— Config 使用的 PageSizeMargin
  • /modules/core/contracts/ —— CryptoPolicyInterfaceDegradationPolicy
  • /modules/core/event/ —— DocumentCreatedEvent 承载 Config
  • /modules/core/exception/ —— InvalidConfigExceptionNotImplementedException

术语表:类型化 wither · 降级策略 · 值对象