PHP 8.4 將支援 HTML 5 的解析

日常分享

自從 PHP 基金會成立以後,PHP 核心維護團隊招募到了許多優秀的新成員,或許是因為有了充足的人力協助開發,PHP 在近幾年的更新下新增了許多功能,讓 PHP 這個老牌語言始終散發著活力。

最新的 8.4 版本即將在今年底正式發佈,這次更新同樣也帶來了許多新功能,其中最讓我眼前為之一亮的新功能是…

PHP 8.4 正式支援 HTML 5 的解析

2024_07_16_18_22_05_c45aaae825f1.jpg
蛤?還不支援 HTML 5 解析?

你可能會想說 HTML 5 都推出這麼久了,PHP 這個 29 歲的老牌語言怎麼到現在都還沒支援?老實說連我也很驚訝。畢竟 HTML 5 在 2008 年推出後到現在已經過了 16 年,我也很好奇為什麼 PHP 始終只支援 HTML 4 的解析。

現在的 PHP 可以使用 DOMDocument 來解析 HTML 4,但如果你嘗試解析 HTML 5 才有的新標籤。

$dom = new DOMDocument();
$dom->loadHTML('<section></section>');

那麼就會得到下面的警告,PHP 會告訴你它不認識這個標籤。

<warning> WARNING </warning> DOMDocument::loadHTML(): Tag section invalid in Entity

解決辦法也是有的,就是請 PHP 無視這個警告。

$dom = new DOMDocument();
$dom->loadHTML('<section></section>', LIBXML_NOERROR);

但有經驗的工程師都知道,這絕對不是解決問題的好方法,因為 HTML 5 相較於 HTML 4 並不只是多了幾個標籤那麼簡單,標籤底下能放哪些標籤的規則也有更動,這會導致 DOMDocument 無法解析出正確的樹狀結構。

如果你有解析 HTML 5 的需求,基本上都會建議使用其他人開發的套件來處理,而不是使用 DOMDocument

為什麼長時間不支援 HTML 5 的解析

PHP 之所以過這麼久都不支援 HTML 5,主要原因是 DOMDocument 背後所使用 libxml2 並不支援 HTML 5 的解析。

libxml2 是一個非常熱門的函式庫,主要用來解析 XML 文件格式,並且可以被許多語言呼叫並使用,例如 C#、Python、Ruby 與 PHP … 等。除了 XML,libxml2 也支援對 HTML 的解析,但只支援到第 4 版。這也是為什麼 PHP 始終沒有支援 HTML 5 解析的原因。

libxml2:我本身就不是設計來處理 HTML 的齁~

其實 libxml2 也正在考慮是否加入對 HTML 5 的支援,但目前提案狀態與薛丁格的貓類似,即可能會支援也可能不會支援,因此 libxml2 官方同樣不建議將 libxml2 用在 HTML 的解析上。

新的 HTML 解析器

PHP 8.4 將採用 Lexbor 作為新的 HTML 解析器。Lexbor 已經被許多知名項目所採用,例如 Python 和 Ruby,因此 PHP 官方認為其可靠程度已經得到驗證,便決定以它做為 PHP 新的 HTML 解析器。

雖然 PHP 8.4 加入了新的 HTML 解析器,但原本的 DOMDocument 並不會被取代掉,你還是可以用它來處理 HTML 4 的解析。至於 HTML 5 的解析將會交給新的類別 HTMLDocument 來處理。如果想搶先玩看看新的 HTMLDocument,可以到 PHP 官方下載 PHP 8.4 的測試版本,或是使用 PHP 核心成員提供的 Dockerfile,來建立擁有新版解析器的 PHP 容器來試玩。

以下就來簡單的試玩一下 HTMLDocument

use DOM\HTMLDocument;

// 你可以將 HTML 5 的內容以字串的方式傳給 HTMLDocument
$dom = HTMLDocument::createFromString('<p id="hello">Hello World!</p>');

// Hello World!
var_dump($dom->getElementById('hello')->nodeValue);

// 因為給的 HTML 結構不完整,所以還是會有警告
// tree error unexpected-token-in-initial-mode in Entity

HTMLDocument 也可以用讀取檔案的方式載入 HTML 5 的內容,首先新增一個 index.html,並在裡面放入 HTML 5 才有的 <nav> 標籤。

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Document</title>
  </head>
  <body>
    <nav class="menu">
      <ul>
        <li><a href="https://www.google.com">google</a></li>
        <li><a href="https://www.microsoft.com/zh-tw">microsoft</a></li>
      </ul>
    </nav>
  </body>
</html>

然後使用 HTMLDocument::createFromFile 來讀取這個檔案。

use DOM\HTMLDocument;

$dom = HTMLDocument::createFromFile("index.html");

foreach ($dom->getElementsByTagName('a') as $a) {
    var_dump($a->getAttribute('href'));
}

// 結果
// string(22) "https://www.google.com"
// string(31) "https://www.microsoft.com/zh-tw"

可以看到新版的 HTML 解析器已經不會有無法辨識 HTML 5 標籤的警告產生。

PHP 8.4 除了新的 HTML 解析器,也加入了很多新的實用功能。身為 PHP Dev,真得很期待年底的更新啊。

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言