Bỏ qua để đến nội dung

Nền tảng PHP 8.4

Spec: ISO 32000-2, §7.5.2 Evidence: Code-backed Ràng buộc PHP: ≥8.4 <9.0

NextPDF yêu cầu PHP 8.4. Trang này giải thích engine dựa vào những tính năng ngôn ngữ 8.4 nào, vì sao phiên bản đó là mức sàn cứng chứ không phải một gợi ý nhẹ, và cách một bản dựng hạ cấp riêng vẫn giữ lựa chọn chạy trên runtime cũ hơn mà không làm suy yếu mã nguồn bạn đang đọc.

Một engine PDF biến đầu vào mơ hồ thành một định dạng tệp chính xác đến từng byte. PDF là một định dạng lâu đời với những quy tắc chắc chắn, cố định, và đủ nghiêm ngặt để một phỏng đoán sai phải trả giá đắt. Ngôn ngữ viết nên engine là tuyến đầu nơi những phỏng đoán đó hoặc bị bắt lỗi, hoặc lọt qua mà không được kiểm tra. Mức sàn phiên bản không phải là một hạn chế đặt ra chỉ để hạn chế. Đó là ranh giới mà khi thấp hơn nó, engine không còn có thể đưa ra những bảo đảm kiểu mà phần còn lại của thiết kế phụ thuộc vào.

Nếu mức sàn đó mơ hồ, sẽ có hai cái giá phải trả. Mã nguồn phình ra vì các lớp đệm tương thích và che khuất logic thật sự. Hệ thống kiểu cũng không còn giữ vai trò chịu lực, trong khi đây chính là đặc tính một pipeline tài liệu không thể để mất.

  • Gói core khai báo "php": ">=8.4 <9.0". Đó là ràng buộc thật, được xác minh trong composer.json, chứ không phải một kỳ vọng chỉ nêu trong tài liệu.
  • 8.4 là mức sàn vì engine dùng các tính năng ngôn ngữ 8.4 (và các bản 8.x gần đây) như những bảo đảm về cấu trúc: asymmetric visibility, backed enum có hành vi, hằng số lớp có kiểu, trạng thái readonly, và named argument hạng nhất trong API công khai.
  • Vẫn có thể chạy trên PHP 8.1–8.3 thông qua một bản dựng hạ cấp riêng (bản backport). Đó là công cụ build, không phải phụ thuộc runtime. Nó không thay đổi mã bạn đọc trong repository core.
  • Giới hạn trên <9.0 là có chủ đích: một bản phát hành PHP major mới được xem là thứ cần kiểm chứng, chứ không phải mặc nhiên tin tưởng.

Mức sàn được quyết định bởi những gì mã thực sự làm. Vì vậy, cách giải thích trung thực là chỉ ra các tính năng ngay trong mã thay vì liệt kê chúng một cách trừu tượng.

Asymmetric visibility cho phép trạng thái được đọc công khai nhưng chỉ được ghi trong phạm vi riêng tư, mà không cần viết tay getter cho từng trường. Rendering context dùng trực tiếp tính năng này:

declare(strict_types=1);
final class RenderingContext
{
// Readable everywhere, writable only inside the class.
public private(set) float $x = 0.0;
public private(set) float $y = 0.0;
public private(set) int $currentPageIndex = -1;
public private(set) string $currentContentStream = '';
}

Chỉ riêng tính năng ngôn ngữ đó đã loại bỏ cả một nhóm thay đổi ngoài ý muốn từ bên ngoài. Con trỏ không thể bị di chuyển từ ngoài engine. Bảo đảm này do runtime thực thi, chứ không dựa vào một quy ước mà người review phải nhớ.

Backed enum có hành vi thay thế các cờ boolean rải rác và hằng số chuỗi bằng một giá trị có kiểu duy nhất, đồng thời tự trả lời được các câu hỏi về chính nó. Bộ phân biệt mức tuân thủ của tài liệu là một backed enum; các phương thức của nó quyết định kết quả ở cấp đặc tả:

declare(strict_types=1);
enum ConformanceMode: string
{
case Plain = 'plain';
case PdfUa2 = 'pdfua2';
case PdfA4 = 'pdfa4';
case PdfA4f = 'pdfa4f';
public function isTagged(): bool
{
return match ($this) {
self::Plain => false,
default => true,
};
}
/** @return 2|3|4|null */
public function pdfaPart(): ?int
{
return match ($this) {
self::PdfA4, self::PdfA4f => 4,
default => null,
};
}
}

Enum này là nguồn chân lý duy nhất cho các câu hỏi “tài liệu này có được gắn thẻ theo đặc tả không?” và “phần ISO nào được áp dụng?”. Khi những câu hỏi đó được biểu diễn bằng các boolean rời rạc, nhiều nơi có thể trả lời chúng không nhất quán.

Hằng số lớp có kiểu khiến ngay cả hằng số cũng trở thành một phần của hợp đồng kiểu. Các giới hạn cứng của engine HTML được khai báo dưới dạng hằng số có kiểu:

private const int MAX_NESTING_DEPTH = 100;
private const int MAX_ELEMENT_COUNT = 50_000;

Named argument là một phần của bề mặt API công khai, không phải một mẹo nội bộ. Các chương trình ví dụ truyền chúng tại những điểm gọi mà người đọc nên sao chép theo:

$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);

Đây không phải là cách dùng cú pháp mới chỉ để trang trí. Mỗi tính năng biến một quy ước mà người review lẽ ra phải tự áp dụng thành một đặc tính do runtime thực thi.

Trang này là Evidence: Code-backed . Mọi tuyên bố ở trên đều ánh xạ tới một tệp trong repository core, chứ không chỉ tới một danh sách tính năng:

  • Ràng buộc phiên bản chính là giá trị require.php ">=8.4 <9.0" trong composer.json của core.
  • Ví dụ asymmetric visibility chính là phong cách khai báo thật trong src/Core/RenderingContext.php (các trường public private(set)).
  • Ví dụ enum phản ánh src/Conformance/ConformanceMode.php, một enum … : string có backing, trong đó các phương thức dựa trên match điều khiển các quyết định tuân thủ.
  • Các hằng số có kiểu nằm ở src/Html/HtmlParser.php (private const int MAX_NESTING_DEPTH, MAX_ELEMENT_COUNT).
  • Lệnh gọi dùng named argument được lấy từ các chương trình examples/ được phát hành kèm theo.

Mức sàn cũng có một khía cạnh tiêu chuẩn. Nhiệm vụ của engine là xuất ra các tệp tuân thủ Spec: ISO 32000-2, §7.5.2 . Một bộ ghi PDF 2.0 tuân thủ phải khai báo phiên bản tài liệu là 2.0 trong phần header của tệp hoặc trong catalog. Đáp ứng một nghĩa vụ chính xác đến vậy dễ dàng hơn nhiều khi ngôn ngữ bên dưới bộ ghi khiến trạng thái không khớp trở nên khó tạo ra ngay từ đầu. Mức sàn phiên bản và sự nghiêm ngặt của định dạng đi cùng nhau.

Chương trình đúng nhỏ nhất đã tận dụng mức sàn này. Nó chạy trên PHP 8.4, dùng một named argument, và tạo ra một tệp tuân thủ:

<?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__ . '/hello.pdf');

Không có gì ở đây là cao siêu cả. Điểm mấu chốt là cùng bộ máy strict typing, enum và asymmetric visibility vốn giúp phần lõi của engine đáng tin cậy đã hoạt động ngay bên dưới chương trình năm dòng này. Bạn không cần chọn bật nó lên.

Cách hiểu sai phổ biến nhất là “yêu cầu PHP 8.4” có nghĩa là “sẽ không hoạt động trừ khi bạn nâng cấp lên 8.4.” Ý đúng là mã nguồn core nhắm tới 8.4. Có một bản dựng hạ cấp riêng dành cho các nhóm bị ghim ở PHP 8.1–8.3.

Cần nói chính xác bản dựng đó thực chất là gì. Đó là một pipeline hạ cấp dựa trên Rector, biến đổi mã nguồn 8.4 thành đầu ra dùng cú pháp cũ hơn. Đó là hạ tầng build, không phải một thư viện runtime để bạn thêm vào danh sách phụ thuộc của ứng dụng. Nó không tạo ra một mã nguồn song song có kiểu yếu hơn. Mã được xem xét trong các trang này và mã được phát hành là cùng một mã. Bản backport là một phép biến đổi áp dụng lên mã đó, chứ không phải một lựa chọn thay thế cho nó.

Trang này giải thích vì sao 8.4 là mức sàn và những gì bản backport giữ lại. Nó không tài liệu hóa cách chạy pipeline hạ cấp, các phiên bản đích được hỗ trợ, hay các lưu ý vận hành của pipeline đó. Những nội dung đó thuộc về tài liệu riêng của bản dựng backport. Bố cục package nội bộ của bộ công cụ đó nằm ngoài phạm vi ở đây. Các cách dùng tính năng được trình bày là minh họa cho phong cách của engine. Chúng không phải bản kiểm kê đầy đủ mọi tính năng 8.x mà mã nguồn sử dụng. Các API chính xác được định nghĩa bởi tài liệu tham chiếu, không phải bởi phần giải thích này. Ràng buộc phiên bản chính xác tính đến ngày xem xét của trang này. Giá trị có thẩm quyền luôn là khối require trong composer.json của core.

Phiên bản (edition) không ảnh hưởng gì đến mức sàn ngôn ngữ. Mọi phiên bản đều được dựng từ cùng một mã nguồn PHP 8.4:

PHP 8.4 source floor — edition availability
Edition Availability
Core Core được viết nhắm tới PHP 8.4.
Pro Pro được xây dựng trên cùng mức sàn mã nguồn 8.4.
Enterprise Enterprise được xây dựng trên cùng mức sàn mã nguồn 8.4.
  • Mức sàn phiên bản — phiên bản PHP tối thiểu mà mã nguồn core nhắm tới (>=8.4). Dưới mức đó, các bảo đảm kiểu của engine không thể được biểu diễn.
  • Asymmetric visibility — một tính năng PHP 8.4 cho phép một thuộc tính đọc được công khai nhưng chỉ ghi được từ một phạm vi hẹp hơn (public private(set)).
  • Backed enum — một enum PHP mà các case có giá trị vô hướng và có thể mang theo hành vi (phương thức), được dùng ở đây như một nguồn chân lý có kiểu duy nhất.
  • Backport — bản dựng hạ cấp riêng dựa trên Rector, biến đổi mã nguồn 8.4 thành đầu ra chạy được trên PHP cũ hơn. Đây là công cụ build, không phải một phụ thuộc runtime.
  • Conformance mode — bộ phân biệt có kiểu của engine cho biết một tài liệu phải thỏa mãn hợp đồng tuân thủ ISO nào.