跳到內容

PHP 8.4 的基礎

Spec: ISO 32000-2, §7.5.2 Evidence: Code-backed PHP 限制: ≥8.4 <9.0

NextPDF 需要 PHP 8.4。本頁說明引擎實際倚賴哪些 8.4 語言特性、為何該版本是硬性底線而非軟性建議,以及一套獨立的降版建置如何在不削弱你正在閱讀的程式碼的前提下,保留於較舊執行環境中執行的選項。

一個 PDF 引擎要把含糊不清的輸入轉換成位元組精確的檔案格式。PDF 是一個歷史悠久的格式,規則穩固且固定,嚴格到只要猜錯一次,代價就很高。引擎所使用的程式語言,正是這些猜測被攔下,或未經檢查就被放行的第一道關卡。版本底線並不是為了限制而限制。它是一條界線;一旦低於這條線,引擎就再也無法提供其設計其餘部分所倚賴的型別保證。

如果這條底線含糊不清,就會帶來兩種代價。程式碼庫會塞滿掩蓋真正邏輯的相容性墊片(shim)。型別系統也會失去承載力,而這正是文件處理管線無法承受失去的特性。

  • 核心套件宣告了 "php": ">=8.4 <9.0"。這才是真正的限制,已在 composer.json 中驗證,而非文件上的期望。
  • 8.4 之所以是底線,是因為引擎把 8.4(以及近期的 8.x)語言特性當作結構性保證來使用:非對稱可見性、帶行為的回溯列舉(backed enum)、具型別的類別常數、readonly 狀態,以及公開 API 中具有第一級地位的具名引數。
  • 透過一套獨立的降版建置(即 backport),仍然可以在 PHP 8.1–8.3 上執行。它是建置工具,而非執行期相依套件。它並不會改變你在核心儲存庫中讀到的程式碼。
  • 上界 <9.0 是刻意設定的:一個全新的 PHP 主要版本被視為需要驗證的對象,而非可以直接假設可用。

底線是由程式碼的實際作為所決定的。因此,誠實的說明方式,是直接呈現這些特性在程式碼中的樣貌,而不是抽象地把它們列成清單。

非對稱可見性讓狀態可以對外公開讀取、卻只能在內部私有寫入,而不必為每個欄位手寫一個 getter。繪製情境(rendering context)直接運用了它:

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 = '';
}

光是這一個語言特性,就消除了一整類意外的外部變動。游標無法從引擎外部被移動。這項保證是由執行環境強制的,而不是靠審查者必須記住的慣例。

帶行為的回溯列舉以一個同時能回答自身相關問題的具型別值,取代散落各處的布林旗標與字串常數。文件符合性鑑別器就是一個回溯列舉,其方法會決定規格層級的結果:

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,
};
}
}

這個列舉是「這份文件是否經規格標記?」以及「適用哪個 ISO 部分?」的單一事實來源。當這些問題以鬆散的布林值表達時,多個地方都可能給出不一致的答案。

具型別的類別常數讓常數也成為型別契約的一部分。HTML 引擎的硬性上限就是以具型別常數宣告的:

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

具名引數是公開 API 介面的一部分,而非內部的小手段。範例程式會在供讀者照抄的呼叫點使用它們:

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

這些都不是為了裝飾而使用新語法。每一項都把一個原本得由審查者手動執行的慣例,轉換成執行環境會強制的特性。

本頁是 Evidence: Code-backed 。上述每一項主張都對應到核心儲存庫中的一個檔案,而非一份特性清單:

  • 版本限制就是核心 composer.json 中的 require.php">=8.4 <9.0"
  • 非對稱可見性的範例就是 src/Core/RenderingContext.php 中實際的宣告風格(public private(set) 欄位)。
  • 列舉範例反映的是 src/Conformance/ConformanceMode.php,一個回溯 enum … : string,其以 match 為基礎的方法驅動了符合性決策。
  • 具型別的常數就是 src/Html/HtmlParser.phpprivate const int MAX_NESTING_DEPTHMAX_ELEMENT_COUNT)。
  • 具名引數的呼叫出自隨附的 examples/ 程式。

這條底線也有標準層面的意義。引擎的工作是輸出符合下列標準的檔案: Spec: ISO 32000-2, §7.5.2 。一個符合規範的 PDF 2.0 寫入器必須在檔案標頭或目錄(catalog)中,將文件版本宣告為 2.0。當寫入器底層的語言讓不一致的狀態從一開始就難以建構時, 要達成這麼精確的義務會容易許多。版本底線與格式的嚴格性是一致的。

最小的正確程式就已經運用到這條底線。它在 PHP 8.4 上執行、使用了一個具名引數,並產生一個符合規範的檔案:

<?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');

這裡沒有任何奇特之處。重點在於:那套讓引擎內部值得信賴的嚴格型別、列舉與非對稱可見性機制,在這支五行程式底下早已啟用。你不需要另外選擇加入。

最常見的誤讀,是把「需要 PHP 8.4」理解成「除非你升級到 8.4,否則無法運作」。它的意思是核心原始碼以 8.4 為目標。對於仍被鎖在 PHP 8.1–8.3 的團隊,另有一套獨立的降版建置存在。

必須精確說明那套建置究竟是什麼。它是一條以 Rector 為基礎的降版管線,會把 8.4 原始碼轉換成較舊語法的輸出。它是建置基礎設施,而非你會加進應用程式相依套件中的執行期函式庫。它並不會引入一份平行、型別較弱的程式碼庫。這些頁面中所審視的程式碼,與實際出貨的程式碼是同一份程式碼。backport 是套用於它的一道轉換,而不是它的替代品。

本頁說明 8.4 為何是底線,以及 backport 保留了什麼。它並不記載如何執行降版管線、其支援的目標版本,或其操作上的注意事項。那些屬於 backport 建置自己的文件。那套工具的內部套件配置不在本頁範圍內。所展示的特性用法是用來說明引擎風格的例子。它們並非程式碼庫所使用的每一項 8.x 特性的完整清單。確切的 API 由參考文件定義,而非由本說明定義。此版本限制在本頁審閱日期當下是準確的。具權威性的值,始終是核心 composer.json 中的 require 區塊。

版本對語言底線沒有任何影響。每一個版本都是從同一份 PHP 8.4 原始碼建置而成:

PHP 8.4 source floor — edition availability
Edition Availability
Core 核心是針對 PHP 8.4 撰寫的。
Pro Pro 建置於同一條 8.4 原始碼底線之上。
Enterprise Enterprise 建置於同一條 8.4 原始碼底線之上。
  • 版本底線 — 核心原始碼所鎖定的最低 PHP 版本(>=8.4)。低於它,引擎的型別保證就無法被表達。
  • 非對稱可見性 — 一項 PHP 8.4 特性,允許屬性對外公開讀取、但只能從較窄的範圍寫入(public private(set))。
  • 回溯列舉 — 一個 PHP 列舉,其各個 case 帶有純量值,並且可以承載行為(方法),在此用作單一的具型別事實來源。
  • Backport — 一套獨立、以 Rector 為基礎的降版建置,會把 8.4 原始碼轉換成可在較舊 PHP 上執行的輸出。它是建置工具,而非執行期相依套件。
  • 符合性模式 — 引擎用以鑑別一份文件必須滿足哪個 ISO 符合性契約的具型別鑑別器。