콘텐츠로 이동

Contracts: 41개의 공개 인터페이스(SPI)

NextPDF\Contracts는 공개 서비스 제공자 인터페이스(SPI)입니다. src/Contracts/ 아래에 있는 41개의 인터페이스와 열거형으로 구성되며, 명시적인 @stability 태그와 하위 호환성 약속을 포함합니다. 확장 패키지, 프레임워크 브리지, Pro 및 Enterprise 에디션은 구체 클래스 대신 이러한 타입을 대상으로 코드를 작성합니다.

Terminal window
composer require nextpdf/core:^3

엔진은 두 가지 표면을 분리합니다. src/Core/, src/Html/, src/Writer/ 아래의 구체 클래스에는 호환성 약속이 적용되지 않습니다. 이러한 클래스는 마이너 버전 사이에서 자유롭게 변경될 수 있습니다. Contracts 네임스페이스는 그 반대입니다. 선언한 안정성 등급에 따라 시그니처가 고정된, 선별된 타입 집합입니다. 엔진 외부의 모든 요소는 이 네임스페이스에 의존하며, 그보다 더 깊은 구현에는 의존하지 않습니다. 여기에는 Laravel, Symfony, CodeIgniter 브리지, compat-tcpdf 심(shim), NextPDF Server, Pro 및 Enterprise 에디션이 포함됩니다.

각 계약은 자체 PHPDoc에서 네 가지 등급 중 하나를 선언합니다. stable 계약은 마이너 또는 패치 릴리스에서 호환성을 깨는 변경을 허용하지 않습니다. 새 메서드는 기본 구현이 함께 제공될 때만 추가됩니다. experimental 계약은 사용 중단 안내와 함께 마이너 릴리스에서 변경될 수 있습니다. deprecated 계약은 대체 대상을 명시합니다. 일부는 계약 전용이며, StreamingWriterInterfaceCursorInterface 등이 이에 해당합니다. 해당 타입은 공개되어 있고 고정되어 있지만, 아직 프로덕션 구현은 제공되지 않습니다.

권위 있는 등급 목록은 docs/extension-points.json입니다(매니페스트 버전 3.0.0, ContractsEvent 전반에 걸쳐 공개된 지점 67개). 기계로 검증 가능한 테스트인 tests/Unit/Contracts/StabilityContractTest.php는 해당 매니페스트를 읽습니다. 이 테스트는 다섯 가지 조건에서 빌드를 실패시킵니다. 첫째는 목록에는 있지만 실제로 누락된 타입입니다. 둘째는 리플렉션으로 확인한 종류가 매니페스트와 일치하지 않는 경우입니다. 셋째는 매니페스트와 맞지 않는 @stability PHPDoc 태그입니다. 넷째는 src/Contracts/ 아래에 있으나 매니페스트에는 없는 계약입니다. 다섯째는 매니페스트에 포함된 @internal 타입입니다. 계약 표면의 변경은 감지되지 않은 채 빠져나갈 수 없습니다.

계약은 아홉 개의 도메인으로 나뉩니다. 각 도메인에는 전용 페이지가 있습니다: 문서 구성, 서명, 바코드 인코딩, 타이포그래피, 보안 정책, 추출, 관찰 가능성, 스트리밍. 이 구분은 통합 담당자가 엔진을 도입하는 방식을 반영합니다. PDF를 생성하려면 document 계약에 의존합니다. 서명을 추가하려면 signing 계약에 의존합니다. 신뢰할 수 없는 HTML을 제약하려면 security-policy 계약에 의존합니다.

선택적 구현을 해석하는 방식은 엔진 전반에서 하나의 패턴을 따릅니다. Core는 class_exists()로 구체 클래스를 확인한 뒤 이를 계약으로 캐스팅합니다. LtvManagerInterfacePdfAManagerInterface는 이 방식으로 Pro 구현을 해석합니다. 따라서 Core는 Apache-2.0 라이선스를 유지하며 상용 코드에 대한 강한 의존성을 갖지 않습니다.

계약종류안정성도입 버전도메인
PdfDocumentInterfaceinterfacestable(안정)1.0.0document(문서)
DocumentFactoryInterfaceinterfacestable(안정)1.7.0document(문서)
ResettableServiceinterfacestable(안정)1.7.0document(문서)
OutputDestinationenumstable(안정)1.0.0document(문서)
Orientationenumstable(안정)1.0.0document(문서)
Alignmentenumstable(안정)1.0.0document(문서)
SignerInterfaceinterfacestable(안정)1.0.0signing(서명)
HsmSignerInterfaceinterfacestable(안정)1.0.0signing(서명)
DeferredSignerInterfaceinterfaceexperimental(실험적)3.0.0signing(서명)
TimestampProviderInterfaceinterfaceexperimental(실험적)3.0.0signing(서명)
LtvManagerInterfaceinterfacestable(안정)1.10.0signing(서명)
CryptoPolicyInterfaceinterfacestable(안정)1.9.0signing(서명)
Barcode1DEncoderInterfaceinterfacestable(안정)1.0.0barcode(바코드)
Barcode2DEncoderInterfaceinterfacestable(안정)1.0.0barcode(바코드)
BarcodeEncoderInterfaceinterfacestable(안정)3.0.0barcode(바코드)
Gs1DataParserInterfaceinterfacestable(안정)1.0.0barcode(바코드)
FontRegistryInterfaceinterfacestable(안정)1.7.0typography(타이포그래피)
TextPreprocessorInterfaceinterfacestable(안정)1.9.0typography(타이포그래피)
HtmlSecurityPolicyInterfaceinterfacestable(안정)3.1.0security-policy(보안 정책)
ExternalResourcePolicyInterfaceinterfacestable(안정)4.0.0security-policy(보안 정책)
InspectorInterfaceinterfaceexperimental(실험적)2.2.0extraction(추출)
EmbeddingServiceInterfaceinterfaceexperimental(실험적)2.1.0extraction(추출)
VectorIndexInterfaceinterfaceexperimental(실험적)2.1.0extraction(추출)
JobNotificationInterfaceinterfaceexperimental(실험적)2.2.0observability(관찰 가능성)
SpectrumInterfaceinterfaceexperimental(실험적)2.1.0observability(관찰 가능성)
StreamingWriterInterfaceinterfaceexperimental(실험적)3.1.0streaming(스트리밍)
CursorInterfaceinterfaceexperimental(실험적)3.1.0streaming(스트리밍)

이 표는 주요 계약을 나열합니다. 나머지 타입인 값 객체 DTO(TextSegment, TextPreprocessResult), EInvoice 하위 네임스페이스, 동작 열거형(DegradationPolicy, UnderlineStyle), 임포트 계약(ImportedFormObjectInterface, EmbeddedPdfObjectInterface, ChromeRenderResultInterface)은 참고 항목 아래의 도메인 페이지에 문서화되어 있습니다. 전체 기계 판독 가능 목록은 docs/extension-points.json이며, .ai/contracts-map.md에 미러링되어 있습니다.

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');

Document::createStandalone()PdfDocumentInterface를 충족하는 구체 Document를 반환합니다. 엔진 내부를 교체 가능하게 유지하려면 자체 서비스에서 해당 인터페이스를 타입 힌트로 사용하세요.

examples/14-worker-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Core\PdfFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Created once at process boot in a RoadRunner/Swoole/Octane worker.
$fontRegistry = new FontRegistry();
$imageRegistry = new ImageRegistry(maxCacheBytes: 50 * 1024 * 1024);
$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$factory = PdfFactory::new()
->withCompress(true)
->withDocumentFactory($documentFactory);
for ($request = 1; $request <= 3; $request++) {
$doc = $factory->create();
$doc->setTitle("Worker Request #{$request}");
$doc->addPage();
$doc->setFont('helvetica', 'B', 16);
$doc->cell(0, 12, "Worker Request #{$request}", newLine: true);
$doc->save(__DIR__ . "/output/14-worker-request-{$request}.pdf");
}

DocumentFactoryDocumentFactoryInterface를 구현합니다. 이 팩토리는 프로세스 수명 동안 유지되는 FontRegistryInterfaceImageRegistryInterface 싱글턴을 보유하며 이를 각 일회성 Document에 주입하므로, 워커는 수천 건의 요청에 걸쳐 각 글꼴을 한 번만 파싱합니다.

  • 계약 전용 타입은 컴파일되지만 런타임 백엔드가 없습니다. newStreamingWriterInterface 또는 CursorInterface에 적용하는 것은 아직 어떤 클래스도 이를 구현하지 않으므로 성공할 수 없습니다. 이들을 전방 선언된 API로 취급하세요.
  • 단일 타입에 대해서는 @stability PHPDoc 태그가 공식 기준입니다. docs/extension-points.json은 타입 집합에 대한 공식 기준입니다. 둘이 일치하지 않으면 StabilityContractTest가 실패합니다. 한쪽을 편집하여 불일치를 숨기지 마세요.
  • experimental은 실제로 불안정하다는 의미가 아니라 호환성 약속이 더 약하다는 의미입니다. 각 계약에 의존하기 전에 .ai/contracts-map.mdbc_promise 필드를 읽어 보세요.
  • 다른 패키지가 기술적으로 참조할 수 있더라도 @internal 클래스는 절대 계약이 아닙니다. 안정성 테스트는 매니페스트에 나타나는 @internal 타입을 거부합니다.
  • 메서드를 stable 인터페이스에 추가하는 것은, 그 메서드가 기본 구현과 함께 제공되지 않는 한 구현자에게 호환성을 깨는 변경입니다. 엔진은 기존 인터페이스를 확장하는 것이 아니라 새 인터페이스를 통해 기능을 추가합니다.

코드를 Contracts를 대상으로 작성해도 측정 가능한 런타임 비용이 추가되지 않습니다. 인터페이스 타입 힌트는 호출할 때마다가 아니라 링크 시점에 해석됩니다. performance_budget은 이 페이지의 워커 예제에 대해 문서 3개 기준으로 벽시계 시간 1500ms, 피크 64MB입니다. 첫 요청의 글꼴 파싱이 그 예산의 대부분을 차지합니다. 이후 요청은 레지스트리 캐시를 재사용하여 계약 때문에 발생하는 작업이 한 자릿수 밀리초로 줄어듭니다. 비용 모델은 계약 디스패치당 O(1)이며, 실제 작업은 각 도메인 페이지에 문서화된 구체 구현에 있습니다.

SPI는 보안 경계이기도 합니다. HtmlSecurityPolicyInterfaceExternalResourcePolicyInterface는 신뢰할 수 없는 HTML이 렌더러에 도달하기 전에 수행할 수 있는 작업을 제약하는 기본 거부(deny-by-default) 계약입니다. CryptoPolicyInterface는 서명 및 암호화에 대한 알고리즘과 키 강도 선택을 제어합니다. 이들은 계약이므로, 통합 담당자는 엔진을 포크하지 않고도 더 엄격한 정책을 제공할 수 있습니다. 보안 관련 정책은 stable 등급에 고정하세요. 실험적(experimental) 정책 계약은 마이너 릴리스 사이에서 형태가 변경될 수 있습니다. 서명 및 보안 정책 도메인 페이지에는 전체 위협 모델과 규범적 참조가 담겨 있습니다.

이 개요는 직접적인 규범적 주장을 하지 않으며, 각 도메인 페이지가 자체 citations 블록을 렌더링합니다. signing 계약은 ISO 32000-2 §12.8(디지털 서명)과 ETSI EN 319 142(PAdES 베이스라인)에 매핑됩니다. PDF/A 관리자는 ISO 19005-4에 매핑됩니다. 절 수준의 적합성 표는 signing, security-policy, extraction 페이지를 참조하세요.

Pro 및 Enterprise 에디션은 여러 핵심 계약 뒤의 프로덕션 코드를 구현합니다: LtvManagerInterface(장기 검증), PdfAManagerInterface(PDF/A 적용), 하드웨어 보안 모듈(HSM) 및 지연 서명자, 바코드 인코더, 임베딩 및 벡터 인덱스 계약. Core는 인터페이스를 공개하고 고정하며, Premium 패키지는 구현을 제공합니다. 이를 통해 오픈 소스 엔진을 Apache-2.0 라이선스로 유지하면서도, 상용 배포에는 API 변경 없는 드롭인 업그레이드를 제공합니다.