ข้ามไปยังเนื้อหา

Contracts: อินเทอร์เฟซสาธารณะ 41 รายการ (SPI)

NextPDF\Contracts คือ service-provider interface (SPI) สาธารณะ ประกอบด้วยอินเทอร์เฟซและ enum จำนวน 41 รายการภายใต้ src/Contracts/ พร้อมแท็ก @stability ที่ระบุชัดเจนและคำมั่นด้านความเข้ากันได้ย้อนหลัง แพ็กเกจส่วนขยาย เฟรมเวิร์กบริดจ์ และรุ่น Pro กับ Enterprise ต่างพึ่งพาชนิดข้อมูลเหล่านี้ ไม่ได้พึ่งพาคลาสรูปธรรม

Terminal window
composer require nextpdf/core:^3

เอนจินเปิดเผยพื้นผิวสองส่วน คลาสรูปธรรมภายใต้ src/Core/, src/Html/ และ src/Writer/ ไม่มีคำมั่นด้านความเข้ากันได้ และอาจเปลี่ยนแปลงได้ระหว่างเวอร์ชันย่อย ส่วนเนมสเปซ Contracts ทำงานต่างออกไป โดยเป็นชุดชนิดข้อมูลที่คัดสรรแล้วและตรึงลายเซ็นไว้ตามระดับความเสถียรที่แต่ละชนิดประกาศ สิ่งใดก็ตามที่อยู่นอกเอนจินจะพึ่งพาเนมสเปซนี้ และไม่พึ่งพาลึกไปกว่านี้ ซึ่งรวมถึงบริดจ์ Laravel, Symfony และ CodeIgniter, ชิม compat-tcpdf, NextPDF Server และรุ่น Pro กับ Enterprise

แต่ละ contract ประกาศระดับความเสถียรหนึ่งในสี่ระดับไว้ใน PHPDoc ของตน contract แบบ stable ไม่อนุญาตให้มีการเปลี่ยนแปลงที่ทำลายความเข้ากันได้ในรีลีสย่อยหรือรีลีสแพตช์ เมธอดใหม่จะเพิ่มได้ก็ต่อเมื่อมี implementation เริ่มต้นมาด้วยเท่านั้น contract แบบ experimental อาจเปลี่ยนแปลงในรีลีสย่อยพร้อมประกาศการเลิกใช้ ส่วน contract แบบ deprecated จะระบุตัวทดแทนของตนไว้ มี contract เพียงส่วนน้อยที่เป็น contract อย่างเดียว เช่น StreamingWriterInterface และ CursorInterface ชนิดข้อมูลเหล่านี้เผยแพร่และตรึงไว้แล้ว แต่ยังไม่มี implementation ระดับใช้งานจริงให้

รายการระดับความเสถียรที่เป็นแหล่งอ้างอิงหลักคือ docs/extension-points.json (แมนิเฟสต์เวอร์ชัน 3.0.0 มีจุดที่เผยแพร่ 67 จุดทั่วทั้ง Contracts และ Event) การทดสอบที่เครื่องตรวจสอบได้ใน tests/Unit/Contracts/StabilityContractTest.php จะอ่านแมนิเฟสต์นั้นและทำให้บิลด์ล้มเหลวเมื่อเกิดหนึ่งในห้าเงื่อนไขต่อไปนี้ หนึ่ง ชนิดข้อมูลที่อยู่ในรายการขาดหายไป สอง ชนิดข้อมูลที่ได้จากรีเฟลกชันไม่ตรงกับแมนิเฟสต์ สาม แท็ก PHPDoc @stability คลาดเคลื่อนไปจากแมนิเฟสต์ สี่ contract ภายใต้ src/Contracts/ ไม่ปรากฏในแมนิเฟสต์ ห้า ชนิดข้อมูลแบบ @internal หลุดเข้าไปในแมนิเฟสต์ พื้นผิว contract จึงไม่อาจคลาดเคลื่อนโดยไม่มีการตรวจพบ

contract แบ่งออกเป็นเก้าโดเมน โดยแต่ละโดเมนมีหน้าเฉพาะของตน ได้แก่ การสร้างเอกสาร การลงนาม การเข้ารหัสบาร์โค้ด การจัดพิมพ์ นโยบายความปลอดภัย การสกัดข้อมูล การสังเกตการณ์ และการสตรีม การแบ่งนี้สะท้อนวิธีนำเอนจินไปใช้งาน คุณพึ่งพา document contract เพื่อสร้างไฟล์ Portable Document Format (PDF) พึ่งพา signing contract เพื่อเพิ่มลายเซ็น และพึ่งพา security-policy contract เพื่อจำกัด HTML ที่ไม่น่าเชื่อถือ

การจำแนก implementation แบบ optional ใช้รูปแบบเดียวกันทั่วทั้งเอนจิน Core ตรวจหาคลาสรูปธรรมด้วย class_exists() แล้วแคสต์เป็น contract LtvManagerInterface และ PdfAManagerInterface จำแนก implementation รุ่น Pro ของตนด้วยวิธีนี้ Core จึงยังคงเป็น Apache-2.0 โดยไม่ผูกกับโค้ดเชิงพาณิชย์อย่างตายตัว

สัญญา (Contract)ชนิดความเสถียรตั้งแต่โดเมน
PdfDocumentInterfaceinterfacestable1.0.0document
DocumentFactoryInterfaceinterfacestable1.7.0document
ResettableServiceinterfacestable1.7.0document
OutputDestinationenumstable1.0.0document
Orientationenumstable1.0.0document
Alignmentenumstable1.0.0document
SignerInterfaceinterfacestable1.0.0signing
HsmSignerInterfaceinterfacestable1.0.0signing
DeferredSignerInterfaceinterfaceexperimental3.0.0signing
TimestampProviderInterfaceinterfaceexperimental3.0.0signing
LtvManagerInterfaceinterfacestable1.10.0signing
CryptoPolicyInterfaceinterfacestable1.9.0signing
Barcode1DEncoderInterfaceinterfacestable1.0.0barcode
Barcode2DEncoderInterfaceinterfacestable1.0.0barcode
BarcodeEncoderInterfaceinterfacestable3.0.0barcode
Gs1DataParserInterfaceinterfacestable1.0.0barcode
FontRegistryInterfaceinterfacestable1.7.0typography
TextPreprocessorInterfaceinterfacestable1.9.0typography
HtmlSecurityPolicyInterfaceinterfacestable3.1.0security-policy
ExternalResourcePolicyInterfaceinterfacestable4.0.0security-policy
InspectorInterfaceinterfaceexperimental2.2.0extraction
EmbeddingServiceInterfaceinterfaceexperimental2.1.0extraction
VectorIndexInterfaceinterfaceexperimental2.1.0extraction
JobNotificationInterfaceinterfaceexperimental2.2.0observability
SpectrumInterfaceinterfaceexperimental2.1.0observability
StreamingWriterInterfaceinterfaceexperimental3.1.0streaming
CursorInterfaceinterfaceexperimental3.1.0streaming

ตารางนี้แสดงรายการ contract หลัก ชนิดข้อมูลที่เหลือ ซึ่งรวมถึง data transfer object (DTO) ของ value-object (TextSegment, TextPreprocessResult), เนมสเปซย่อย EInvoice, enum สำหรับพฤติกรรม (DegradationPolicy, UnderlineStyle) และ import contract (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() คืนค่า Document รูปธรรมที่สอดคล้องกับ PdfDocumentInterface ให้ระบุชนิดเป็นอินเทอร์เฟซในเซอร์วิสของคุณ เพื่อให้ภายในของเอนจินยังสลับเปลี่ยนได้

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");
}

DocumentFactory implements DocumentFactoryInterface โดยถือ singleton ของ FontRegistryInterface และ ImageRegistryInterface ที่มีอายุเท่ากับโพรเซส แล้วฉีดเข้าไปในแต่ละ Document ที่ใช้แล้วทิ้ง ดังนั้น worker จึงแจงฟอนต์แต่ละตัวเพียงครั้งเดียวตลอดคำขอนับพันครั้ง

  • ชนิดข้อมูลที่เป็น contract เพียงอย่างเดียวจะคอมไพล์ได้ แต่ไม่มีการรองรับขณะรันไทม์ นิพจน์ new ที่ใช้กับ StreamingWriterInterface หรือ CursorInterface จะไม่สำเร็จ เพราะยังไม่มีคลาสใด implement ชนิดข้อมูลเหล่านั้น ให้ปฏิบัติต่อชนิดข้อมูลเหล่านี้เสมือน application programming interface (API) ที่ประกาศไว้ล่วงหน้า
  • แท็ก PHPDoc @stability คือแหล่งอ้างอิงหลักสำหรับชนิดข้อมูลเดี่ยว docs/extension-points.json คือแหล่งอ้างอิงหลักสำหรับทั้งชุด เมื่อทั้งสองไม่ตรงกัน StabilityContractTest จะล้มเหลว อย่าซ่อนความไม่ตรงกันด้วยการแก้ไขเพียงด้านใดด้านหนึ่ง
  • experimental ไม่ได้หมายความว่าไม่เสถียรในทางปฏิบัติ แต่หมายความว่าคำมั่นด้านความเข้ากันได้อ่อนกว่า อ่านฟิลด์ bc_promise ของแต่ละ contract ใน .ai/contracts-map.md ก่อนตรึงเข้ากับ contract นั้น
  • คลาสแบบ @internal ไม่เคยเป็น contract แม้ว่าแพ็กเกจอื่นจะอ้างอิงถึงได้ในทางเทคนิคก็ตาม การทดสอบความเสถียรจะปฏิเสธชนิดข้อมูลแบบ @internal ใดก็ตามที่ปรากฏในแมนิเฟสต์
  • การเพิ่มเมธอดเข้าไปในอินเทอร์เฟซแบบ stable เป็นการเปลี่ยนแปลงที่ทำลายความเข้ากันได้สำหรับผู้ทำ implementation เว้นแต่เมธอดนั้นจะมาพร้อม implementation เริ่มต้น เอนจินเพิ่มความสามารถผ่านอินเทอร์เฟซใหม่ ไม่ใช่ด้วยการขยายอินเทอร์เฟซที่มีอยู่เดิม

การเขียนโปรแกรมโดยอาศัย Contracts ไม่เพิ่มต้นทุนขณะรันไทม์ที่วัดได้ การระบุชนิดเป็นอินเทอร์เฟซจะถูกจำแนกที่เวลาลิงก์ ไม่ใช่ต่อการเรียกแต่ละครั้ง performance_budget สำหรับตัวอย่าง worker ของหน้านี้คือ 1500 ms wall และ 64 MB peak ตลอดสามเอกสาร การแจงฟอนต์ในคำขอแรกใช้สัดส่วนหลักของงบประมาณนั้น คำขอถัดมาใช้แคชของรีจิสทรีซ้ำ และลดลงเหลืองานที่ระบุได้ว่าเกิดจาก contract ในระดับมิลลิวินาทีหลักหน่วย แบบจำลองต้นทุนเป็น O(1) ต่อการดิสแพตช์ contract หนึ่งครั้ง งานจริงอยู่ใน implementation รูปธรรม ซึ่งบันทึกไว้ในหน้าโดเมนแต่ละหน้า

SPI ยังเป็นขอบเขตด้านความปลอดภัยด้วย HtmlSecurityPolicyInterface และ ExternalResourcePolicyInterface เป็น contract แบบปฏิเสธโดยค่าเริ่มต้น ซึ่งจำกัดสิ่งที่ HTML ที่ไม่น่าเชื่อถือทำได้ก่อนจะไปถึงตัวเรนเดอร์ CryptoPolicyInterface ควบคุมการเลือกอัลกอริทึมและความแข็งแรงของคีย์สำหรับการลงนามและการเข้ารหัสลับ เพราะสิ่งเหล่านี้เป็น contract คุณจึงจัดหานโยบายที่เข้มงวดกว่าได้โดยไม่ต้องฟอร์กเอนจิน ให้ตรึงเข้ากับระดับ stable สำหรับนโยบายใดก็ตามที่เกี่ยวข้องกับความปลอดภัย contract นโยบายแบบ experimental อาจเปลี่ยนรูปแบบระหว่างรีลีสย่อยได้ หน้าโดเมนการลงนามและนโยบายความปลอดภัยมีแบบจำลองภัยคุกคามฉบับเต็มและการอ้างอิงเชิงบรรทัดฐาน

ภาพรวมนี้ไม่กล่าวอ้างเชิงบรรทัดฐานโดยตรง หน้าโดเมนแต่ละหน้าจะแสดงบล็อก citations ของตนเอง signing contract แมปเข้ากับ ISO 32000-2 §12.8 (ลายเซ็นดิจิทัล) และ ETSI EN 319 142 (เบสไลน์ PAdES) ตัวจัดการ PDF/A แมปเข้ากับ ISO 19005-4 ดูหน้าการลงนาม นโยบายความปลอดภัย และการสกัดข้อมูลสำหรับตารางความสอดคล้องระดับเคลาส์

รุ่น Pro และ Enterprise จัดหาโค้ดระดับใช้งานจริงที่อยู่เบื้องหลัง core contract หลายรายการ ได้แก่ LtvManagerInterface (long-term validation), PdfAManagerInterface (การบังคับใช้ PDF/A), Hardware Security Module (HSM) และ deferred signer, ตัวเข้ารหัสบาร์โค้ด รวมทั้ง embedding และ vector-index contract Core เผยแพร่และตรึงอินเทอร์เฟซ ส่วนแพ็กเกจ Premium จัดส่ง implementation วิธีนี้ทำให้เอนจินโอเพนซอร์สยังคงเป็น Apache-2.0 และมอบการอัปเกรดแบบดรอปอินให้แก่การนำไปใช้งานเชิงพาณิชย์โดยไม่เปลี่ยนแปลง API

  • Contracts / Document — contract สำหรับเอกสาร PDF, แฟกทอรี และรีจิสทรี
  • Contracts / Signing — contract สำหรับ signer, HSM, timestamp และ long-term validation (LTV)
  • Contracts / Security Policy — contract สำหรับ crypto, HTML และนโยบายทรัพยากร
  • Contracts / Typography — contract สำหรับ font registry และการประมวลผลข้อความล่วงหน้า
  • Contracts / Extraction — contract สำหรับ inspector, PDF/A, embedding และ e-invoice
  • Core — คลาสรูปธรรมที่สอดคล้องกับ contract เหล่านี้
  • Event — event SPI ที่เป็นคู่ขนาน เผยแพร่ควบคู่ไปกับ Contracts