계약 / 문서
한눈에 보기
섹션 제목: “한눈에 보기”문서 도메인은 PDF를 작성할 때 기준이 되는 계약을 담고 있습니다. 여기에는 콘텐츠용 PdfDocumentInterface, 워커 환경에서 안전하게 생성하기 위한 DocumentFactoryInterface, 글꼴 및 이미지 레지스트리 계약, 그리고 세 가지 전달 및 레이아웃 열거형이 포함됩니다. 모두 1.0.0 또는 1.7.0 이후 stable 상태입니다.
composer require nextpdf/core:^3개념 개요
섹션 제목: “개념 개요”PdfDocumentInterface는 기본 API 표면입니다. 페이지 관리, 글꼴 선택, 셀과 멀티셀 텍스트 레이아웃, HTML 렌더링, 이미지 임베딩, 최종 출력을 정의합니다. 모든 메서드는 static을 반환하므로 호출을 체이닝할 수 있습니다. Document::createStandalone()는 이 인터페이스를 충족하는 구체 인스턴스를 반환합니다. 직접 작성하는 서비스에서는 이 인터페이스를 타입 힌트로 사용하십시오. 그러면 엔진 내부 구현을 교체 가능한 상태로 유지할 수 있습니다.
문서 생성 경로는 두 가지입니다. 일반적인 PHP-FPM 요청에서는 createStandalone()가 전용 레지스트리를 갖춘 자체 완결 문서를 생성합니다. 장시간 실행되는 워커는 다른 경로를 사용하며, RoadRunner, Swoole, Laravel Octane이 여기에 해당합니다. 이 경우 DocumentFactoryInterface::create()는 매번 새로운 일회용 Document를 반환합니다. 문서는 프로세스 수명 주기 동안 유지되는 레지스트리에서 데이터를 읽지만, 절대 변경하지 않습니다. 팩토리는 FontRegistryInterface 및 ImageRegistryInterface 싱글턴을 유지합니다. 각 문서에는 자체 렌더링 컨텍스트와 라이터가 있습니다. 이 구조가 장애 격리를 제공합니다. 한 문서가 다른 문서가 의존하는 공유 상태를 손상시킬 수 없습니다.
레지스트리 계약 덕분에 워커는 빠르게 동작합니다. FontRegistryInterface는 글꼴 파일을 한 번만 파싱하고, 파싱된 메타데이터를 프로세스 수명 동안 캐시합니다. 워밍업 후에는 잠글 수 있어 프로덕션 트래픽이 이를 변경할 수 없습니다. ImageRegistryInterface는 디코딩된 이미지 바이너리 데이터를 용량이 제한된 LRU(가장 오래 사용되지 않은 항목 우선) 정책에 따라 캐시합니다. 이미지 메타데이터는 바이너리가 제거된 후에도 메모리에 남습니다. 두 인터페이스 모두 용량 계획을 위해 memoryUsage()를 제공합니다. ImageRegistryInterface는 ResettableService를 확장합니다. 이 계약은 구조적 메타데이터를 손상하지 않고 캐시된 데이터를 제거합니다. 워커는 메모리 압박 상황에서 이미지 캐시를 폐기하면서도 서비스를 계속할 수 있습니다.
세 가지 열거형이 도메인을 완성합니다. OutputDestination은 인라인 표시, 강제 다운로드, 파일 시스템 쓰기, 원시 문자열 반환 중 하나를 선택합니다. Orientation은 세로 또는 가로 방향을 선택합니다. Alignment는 왼쪽, 가운데, 오른쪽 또는 양쪽 맞춤 텍스트 정렬을 선택합니다. 각 열거형의 케이스는 레거시 TCPDF 코드를 값으로 가집니다. 따라서 compat-tcpdf 브리지는 깔끔하게 매핑됩니다. 이 열거형의 하위 호환성 약속은 추가만 허용하는 방식입니다. 어떤 케이스도 제거되지 않습니다. 새 케이스는 마이너 릴리스에서 추가될 수 있습니다.
API 표면
섹션 제목: “API 표면”| 유형 | 종류 | 주요 멤버 | 안정성 | 도입 버전 |
|---|---|---|---|---|
PdfDocumentInterface | interface | addPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save() | 안정 | 1.0.0 |
DocumentFactoryInterface | interface | create(?Config): Document | 안정 | 1.7.0 |
ResettableService | interface | reset(): void | 안정 | 1.7.0 |
FontRegistryInterface | interface | register(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage() | 안정 | 1.7.0 |
ImageRegistryInterface | interface | load(), loadFromString(), getMetadata(), memoryUsage() (ResettableService 확장) | 안정 | 2.0.0 |
OutputDestination | enum (string) | Inline, Download, File, String | 안정 | 1.0.0 |
Orientation | enum (string) | Portrait, Landscape | 안정 | 1.0.0 |
Alignment | enum (string) | Left, Center, Right, Justify | 안정 | 1.0.0 |
FontRegistryInterface 및 ImageRegistryInterface는 타이포그래피 페이지에 상세히 문서화되어 있으며, 이 문서 페이지에서는 생성 수명 주기에서 이들이 맡는 역할을 다룹니다.
코드 예제 — 빠른 시작
섹션 제목: “코드 예제 — 빠른 시작”<?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->setFont('helvetica', '', 12);$doc->cell(0, 10, 'This is a minimal PDF generated with NextPDF.', newLine: true);$doc->save(__DIR__ . '/output/01-hello-world.pdf');코드 예제 — 프로덕션
섹션 제목: “코드 예제 — 프로덕션”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\PdfFactory;use NextPDF\ValueObjects\{Margin, PageSize};
$factory = PdfFactory::new() ->withPageSize(PageSize::A4()) ->withMargins(new Margin(15.0, 15.0, 15.0, 15.0)) ->withCompress(true) ->withLang('en');
// The same configured factory creates independent documents.$doc = $factory->create();$doc->setTitle('PdfFactory Example');$doc->setAuthor('NextPDF');$doc->addPage();$doc->setFont('helvetica', '', 16);$doc->cell(0, 12, 'Created via PdfFactory', newLine: true);
$doc2 = $factory->create();$doc2->addPage();$doc2->setFont('helvetica', '', 12);$doc2->cell(0, 10, 'Second document from the same factory.');
$doc->save(__DIR__ . '/output/02-pdf-factory.pdf');PdfFactory는 불변 빌더이며, 각 with*()는 새 인스턴스를 반환합니다. 내부적으로 DocumentFactoryInterface를 구성하므로, 개요에서 설명한 워커 레지스트리 모델이 추가 연결 코드 없이 적용됩니다.
엣지 케이스 및 주의사항
섹션 제목: “엣지 케이스 및 주의사항”createStandalone()는 전용 레지스트리를 생성합니다. 워커 루프에서는 요청마다 모든 글꼴을 다시 파싱하게 됩니다. 대신 공유 레지스트리를 사용하는DocumentFactoryInterface를 사용하십시오.- 하나의
Document는 설계상 일회용입니다. 여러 논리적 문서에서 하나의 인스턴스를 재사용하면 상태가 누출됩니다. 문서마다create()를 호출하고 가비지 컬렉션에 회수를 맡기십시오. FontRegistryInterface::lock()를 호출하면register(),addFontDirectory(),warmup()가LogicException을 던집니다. 워밍업 이후에 잠그고, 요청 처리 중에는 절대 잠그지 마십시오.OutputDestination::File은 서버 파일 시스템에 기록하고 원시 바이트를 반환합니다.save()는 명시적인 파일 경로를 사용합니다. 같은 문서에서 이 둘을 혼용하지 마십시오.cell()은 TCPDF 호환성을 위해 border 인수로bool|string을 허용하며, 빈 문자열은false와 동일하지 않습니다. 의도한 타입의 값을 정확히 전달하십시오.
글꼴 및 이미지 레지스트리는 문서 도메인을 요청 단위 시스템이 아니라 메모리 한도 기반 시스템으로 만듭니다. 첫 요청의 글꼴 파싱이 가장 큰 비중을 차지합니다. performance_budget은 워커 예제에서 세 개의 문서에 걸쳐 실제 경과 시간 1500ms, 피크 메모리 64MB입니다. 이 예산의 대부분은 첫 글꼴 파싱에 사용됩니다. 워밍업 이후에는 계약 때문에 발생하는 문서당 작업이 O(1)이며, 그 작업은 레지스트리 조회와 컨텍스트 할당입니다. 어느 레지스트리에서든 memoryUsage()는 실시간 용량 계획을 위해 MemoryReport를 반환합니다. ResettableService::reset()는 지속 부하 상황에서 피크 메모리를 제한합니다.
보안 참고사항
섹션 제목: “보안 참고사항”문서 계약에는 암호화 관련 표면이 없지만, 두 가지 운영상 위험이 적용됩니다. 첫째, image()는 경로 또는 URL을 허용합니다. 신뢰할 수 없는 입력을 다루는 경우 사용자가 제어하는 URL을 직접 전달하지 말고, ExternalResourcePolicyInterface를 통해 원격 페치를 제한하십시오(보안 정책 페이지 참조). 둘째, writeHtml()는 HTML 파이프라인의 진입점입니다. 신뢰할 수 없는 마크업은 렌더링 전에 HtmlSecurityPolicyInterface를 통과해야 합니다. 문서 계층 자체는 새니타이즈를 수행하지 않습니다. 이는 보안 정책 도메인의 역할이며, 계약으로 분리되어 있으므로 포크 없이도 더 엄격한 정책을 제공할 수 있습니다.
적합성
섹션 제목: “적합성”문서 계약은 ISO 32000-2에 정의된 PDF 2.0 문서 구조를 구현합니다. 출력, 페이지, 글꼴 처리는 ISO 32000-2 §7에 따라 간접 객체와 상호 참조 스트림을 생성합니다. 콘텐츠는 엔진 계층 계약(ADR-010)에 따라 라이터 계층을 통해 출력됩니다. 이 페이지에서는 구조적 적합성을 넘어서는 조항 수준의 주장을 하지 않습니다. PDF/A 및 PDF/UA 적합성은 규범 표가 포함된 추출 및 접근성 페이지에 문서화되어 있습니다.
참고 항목
섹션 제목: “참고 항목”- 계약: 41개의 공개 인터페이스(SPI) — SPI 개요와 안정성 등급.
- 계약 / 타이포그래피 —
FontRegistryInterface가 상세히 문서화되어 있습니다. - 계약 / 보안 정책 —
writeHtml()및image()를 제어하는 정책. - Core —
Document및PdfFactory구체 클래스. - Document — 문서 생성 모듈.
- Writer — 이 계약들에 따라 PDF 객체를 출력하는 계층.