DevTips – PHP 中的命名空間

已發表: 2020-03-06

大約一年前,WordPress 決定將所需的最低 PHP 版本從 5.2(自 2010 年開始使用)更新為最新版本。 事實上,今天 WordPress 推薦的 PHP 最低版本是最新版本之一:PHP 7.3。

如果您是一個簡單的 WordPress 用戶,這可能不會對您產生太大影響(除了這些新版本提供更好的性能之外)。

但是,如果您是開發人員,這些新的 PHP 版本有一些很棒的功能可以在您的插件和主題中使用。 今天,具體來說,我想和你談談一個已經與我們在一起很長時間的東西:命名空間。

WordPress 和代碼前綴

作為 WordPress 開發人員,您學習的首要規則之一是“在我們所做的一切中使用前綴”以避免“名稱衝突”。 正如我們在 WordPress 最佳實踐中所讀到的:

當您的插件使用與另一個插件相同的變量、函數或類名稱時,就會發生命名衝突。

[為避免名稱衝突],所有變量、函數和類都應以唯一標識符作為前綴。 前綴可防止其他插件覆蓋您的變量並意外調用您的函數和類。 它也會阻止你做同樣的事情。

開發 WordPress 插件的最佳實踐

因此,例如,與其創建類似get_site_id的函數,不如將其命名為nelio_content_get_site_id 。 這樣,我們能夠快速識別某個函數 ( get_site_id ) 所屬的插件 ( nelio_content ) 或主題,並避免在多個插件嘗試定義相同函數時出現致命錯誤。

使用前綴是創建“命名空間”的基本方法; 當我們沒有更好的選擇時,我們必須實施一種解決方法。 所有使用相同前綴的元素都是相同集合或命名空間的一部分。 但這會導致不必要的更複雜的代碼:名稱更長是因為前綴除了模擬命名空間之外沒有其他用途。

PHP 命名空間

PHP 5.3 版引入了命名空間的概念。 他們在文檔中給出的定義對我來說似乎很好,所以我在這裡複製它:

在最廣泛的定義中,命名空間是一種封裝項目的方式。 這在很多地方都可以看作是一個抽象的概念。 例如,在任何操作系統中,目錄用於對相關文件進行分組,並充當其中文件的命名空間。 作為一個具體的例子,文件foo.txt可以同時存在於目錄/home/greg/home/other中,但是foo.txt的兩個副本不能共存於同一目錄中。

在 PHP 世界中,命名空間旨在解決庫和應用程序的作者在創建可重用代碼元素(如類或函數)時遇到的兩個問題:

1. 您創建的代碼與內部 PHP 代碼或第三方代碼之間的名稱衝突。

2. 別名(或縮短) Extra_Long_Names的能力,提高源代碼的可讀性。

PHP 文檔

如何創建命名空間

在 PHP 中創建命名空間非常容易。 在您創建的 PHP 文件的開頭,添加一個帶有您要使用的名稱的namespace指令,並且您在該文件中定義的“所有內容”都將屬於該命名空間:

 <?php namespace Nelio_Content;

是的,就是這麼簡單! 現在,我們在那裡創建的“一切”都將位於Nelio_Content命名空間中。 例如,如果我定義一個像我在開頭提到的那樣的函數:

 <?php namespace Nelio_Content; function get_site_id() { // ... }

我們現在知道get_site_idNelio_Content命名空間內。 這樣,我們在定義函數時就不再需要使用nelio_content_前綴了。 偉大的!

命名空間的例外

如果您仔細查看到目前為止我告訴您的內容,您會發現我一直在引號中寫“所有內容”:“我們添加的所有內容都將屬於指定的名稱空間。” 我為什麼這樣做? 因為命名空間並不絕對適用於我們編寫的所有代碼……有一些例外。

PHP 命名空間僅涵蓋以下 PHP 元素:

  • 課程
  • 接口
  • 性狀
  • 職能
  • const聲明但沒有用define聲明的常量

此外,WordPress 中還有一些額外的東西也需要它們自己的命名空間,不幸的是,PHP 命名空間不包括:您的腳本句柄、數據庫選項或自定義內容類型及其元數據等。在所有這些情況下,您必須繼續使用前綴。

如何將元素從一個命名空間導入到另一個命名空間

如果您需要使用您自己的命名空間中的元素,您不必做任何特別的事情:只需通過它的名稱來調用它。 例如,在以下代碼片段中:

 <?php namespace Nelio_Content; function get_site_id() { // ... } function get_auth_token() { $site_id = get_site_id(); // ... }

您可以看到我們定義了兩個函數: get_site_idget_auth_token ,都在Nelio_Content命名空間中。 當get_auth_token需要使用get_site_id時,它就像往常一樣簡單地調用它。

另一方面,如果您需要在不同的命名空間中使用get_site_id ,則必須使用其完整標識符調用該函數:

 <?php namespace Something_Else; function do_some_action() { $site_id = Nelio_Content\get_site_id(); // ... }

或者您必須使用關鍵字use導入函數:

 <?php namespace Something_Else; use Nelio_Content\get_site_id; function do_some_action() { $site_id = get_site_id(); // ... }

我個人非常喜歡第二個選項:使用關鍵字use從其他命名空間導入函數,您可以快速查看文件的標題並確定其依賴項。

帶有 PHP 命名空間的 WordPress 過濾器和操作

在 WordPress 過濾器和操作旁邊使用命名空間時,您應該記住一個重要的細節。 當您指定過濾器和操作回調時,通常通過將回調名稱作為字符串提供:

 <?php // ... add_action( 'init', 'do_some_action' );

問題是,如果這個函數在一個命名空間內,之前的鉤子將無法按預期工作; 你必須告訴 WordPress 函數的全名。 換句話說,你必須包含它的命名空間(如果有的話)。

您是否在定義命名空間本身的文件中添加了鉤子? 沒關係,用全名:

 <?php namespace Nelio_Content; function do_some_action() { // ... } add_action( 'init', 'Nelio_Content\do_some_action' );

您是否在另一個命名空間中,但您use導入了該函數? 也沒關係,用全名:

 <?php namespace Something_Else; use Nelio_Content\do_some_action; // ... add_action( 'init', 'Nelio_Content\do_some_action' );

在我們的命名空間中使用別名

命名空間的另一個非常有趣的功能是別名。 想像以下場景:

 <?php namespace Nelio_Content; function get_site_id() { // ... }

如果我想在另一個命名空間中使用這個函數,我們已經看到我可以use來實現。 但是,如果我想在其中使用它的模塊已經有一個名為get_site_id的函數,我將如何使用這個函數?

好吧,對我來說幸運的是,我們可以將我們的導入別名為新名稱:

 <?php namespace Something_Else; use Nelio_Content\get_site_id as get_nc_site_id(); function get_site_id() { // ... } function do_some_action() { $nc_site_idd = get_nc_site_id(); // ... }

立即開始使用命名空間!

命名空間是避免名稱衝突和組織代碼的絕佳工具。 事實上,雖然我沒有對這篇文章發表評論,但有一些標準(例如 PSR-4)允許 PHP 根據您使用的命名空間的結構以及您如何將代碼組織到目錄和文件中來自動加載類。

如果您還沒有在項目中使用命名空間,我們建議您從現在開始這樣做。 在評論中告訴我們您的經歷!

Chaitanya Tvs 在 Unsplash 上的精選圖片。