聲明:這篇文章以 Modern PHP 為藍本,以 Laravel 原始碼為實例進行敘述,以便大家研究底層原始碼更加輕鬆。
1、什麼是命名空間
#如果你只需要知道現代PHP特性中的一個,那就應該是命名空間。命名空間在PHP5.3.0中引入,其作用是依照一個虛擬的層次結構組織PHP程式碼,這種層次結構類似作業系統中檔案系統的目錄結構。
【相關推薦:PHP教學】
命名空間是現代PHP元件生態的基礎,現代的PHP元件框架程式碼都是放在各自全局唯一的廠商命名空間中,以免和其他廠商使用的常見類別名稱衝突。
下面我來看看真實的PHP元件是如何使用命名空間的。 Laravel框架中的Http元件用來管理HTTP請求和回應,這個元件用到了常見的類別名,例如Request、Response,許多其他PHP元件也用到了這樣的類別名,既然其他PHP程式碼也用到了相同的類名,那要怎麼使用這個組件呢?
其實我們可以放心使用,因為這個元件的程式碼放在了唯一的廠商命名空間Illuminate
。
打開這個元件在GitHub中的倉庫(https://github.com/laravel/framework/blob/master/src/Illuminate/Http/Response.php),找到Response.php
檔:
第3行程式碼如下:
namespace Illuminate\Http;
這一行是PHP命名空間聲明語句,聲明命名空間的程式碼總是應該放在標籤後的第一行。透過這個命名空間的宣告語句我們可以看到
Response
位於廠商命名空間Illuminate
中(最頂層命名空間),我們也看到Response
類別在子命名空間Http
中,你可以看下和Response.php
文件在同一層級的其他文件,會發現它們都使用相同的命名空間聲明語句。
命名空間的作用是封裝和組織相關的PHP類,就像在檔案系統中把相關的檔案放在同一個目錄中一樣。 PHP命名空間和作業系統的實體檔案系統不同,這是一個虛擬概念,沒必要和檔案系統中的目錄結構完全相同,雖然如此,但是大多數PHP元件為了相容於廣泛使用的PSR-4自動載入標準,會把命名空間放到對應檔案系統的子目錄中。
2、為什麼使用命名空間
前面已經提到過,我們的程式碼可能和其他開發者的程式碼使用相同的類名、介面名、函數或常數名,如果不使用命名空間,名稱會發生衝突,導致PHP執行出錯。而使用命名空間將程式碼放到唯一的廠商命名空間,我們的程式碼就可以和其他開發者使用相同的類別名稱、介面名稱、函數或常數名稱。
當然如果你開發的是小型個人項目,只有少量的依賴,類名衝突可能不是問題,但是如果在團隊中工作,開發用到許多第三方依賴的大型項目,就要認真對待命名衝突問題,因為你無法控制專案依賴在全域命名空間中引入的類別、介面、函數和常數,這也是為什麼要使用命名空間的原因。
3、宣告命名空間
每個PHP類別、介面、函數和常數都在命名空間中,宣告命名空間很簡單,在標籤後的第一行聲明,聲明語句以
namespace
開頭,隨後是一個空格,然後是命名空間的名稱,最後以;
結尾。
命名空間常用於設定頂層廠商名,例如我們設定廠商名為LaravelAcademy
:
登入後複製
在這個命名空間宣告語句後宣告的所有PHP類別、介面、函數和常數都在LaravelAcademy
命名空間中,而且和Laravel學院有某種關係。如果我們想組織學院用到的代碼該怎麼做呢?答案是使用子命名空間。
子命名空間的宣告方式和前面的範例完全一樣,唯一的差異是我們要使用\
符號把命名空間和子命名空間分開,例如:
登入後複製
這個命名空間後的所有類別、介面、函數和常數都位於LaravelAcademy\ModernPHP
中。在同一個命名空間中的類別沒必要在同一個PHP檔案中聲明,可以在PHP檔案的頂部指定一個命名空間或子命名空間,此時,這個檔案的程式碼就是該命名空間或子命名空間的一部分。因此我們可以在不同文件中編寫屬於同一個命名空間的多個類別。
注:厂商命名空间是最顶层的命名空间,也是最重要的命名空间,用于识别品牌或组织,必须具有全局唯一性。子命名空间相对而言没那么重要,但是可以用于组织项目的代码。
4、导入和别名
在命名空间出现之前,PHP开发者使用Zend风格的类名解决命名冲突问题,这是一种类的命名方案,因Zend框架而流行,这种命名方案在PHP类名中使用下划线的方式表示文件系统的目录分隔符。这种约定有两个作用:其一,确保类名是唯一的;其二,原生的自动加载器会把类名中的下划线替换成文件系统的目录分隔符,从而确定文件的路径。例如,Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query
类对应的文件是Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php
。可以看出,这种命名有个缺点:类名特别长。
现代的PHP命名空间也有这个问题,例如上述Response
类完整的全名是Illuminate\Http\Response
,幸好,我们可以通过导入以及创建别名的方式来改变这一状况。
导入的意思是指,在每个PHP文件中告诉PHP想使用哪个命名空间、类、接口、函数和常量,导入后就不用使用全名了:
send();
我们通过use
关键字告诉PHP,我们想使用Illuminate\Http\Response
类,我们只需要输入一次完全限定的类名,随后实例化Response
的时候,无需使用完整的类名。
如果觉得这样的类名还是长,可以创建别名。创建别名指的是告诉PHP我要使用简单的名称引用导入的类、接口、函数或常量:
send();
从PHP 5.6开始还可以导入函数和常量,不过要调整use关键字的句法,如果要导入函数,需要使用use func
:
登入後複製
如果想导入常量,可以使用use constant
:
登入後複製
当然也支持别名,创建方式和类一样。
5、实用技巧
多重导入
如果想要在PHP文件中导入多个类、接口、函数或常量,需要在PHP文件的顶部使用多个use语句,PHP支持用简短的语法把多个use语句写成一行:
登入後複製
但是为了可读性,建议不要这么写,还是一行写一个use语句比较好:
登入後複製
一个文件使用多个命名空间
PHP允许在一个文件中定义多个命名空间:
登入後複製
但这么做不好,违背了“一个文件一个类”的良好实践,因此不建议这么做。
全局命名空间
如果引用的类、接口、函数和常量没有指定命名空间,PHP假定引用的类、接口、函数和常量在当前的命名空间中。如果要使用其他命名空间的类、接口、函数或常量,需要使用完全限定的PHP类名(命名空间+类名)。
有些代码在全局命名空间中,没有命名空间,比如原生的Exception类就是这样。在命名空间中引用全局的代码时,需要在类、接口、函数或常量前加\
符号:
登入後複製
自动加载
命名空间还为PHP-FIG制定的PSR-4自动加载标准奠定了坚实的基础,大多数现代的PHP组件都使用了这种自动加载模式,使用依赖管理器Composer可以自动加载项目的依赖,后续我们还会详细介绍Composer和PHP-FIG,现在你只需要知道没有命名空间,就没有现代的PHP生态系统和基于组件的新型架构,由此可见命名空间的重要性。
相关学习推荐:PHP编程从入门到精通
以上是PHP中什麼是命名空間?為什麼要使用命名空間?的詳細內容。更多資訊請關注PHP中文網其他相關文章!