php命名空間簡介

如下是我對命名空間的一些體會和理解,最好先看下php的官方文檔再來看此文,會更好一點。因爲水平有限,文中若有紕漏,但願指出php

前言

在php5.3以上的版本中,php引入了命名空間(如下稱呼爲namespace)這個性能。我的認爲,這是很是重要的一項改變。之因此說重要,並非說namespace自己有多麼牛逼或者多高的技術含量。而是因爲命名空間的引入,引發了一些列的連鎖反應,這些連鎖反應給咱們如今phper開發者提供了另外一種可能。linux

如今的開發方式程序員


咱們在以往開發應用的時候,即便是很是簡單的應用,也常用php的那些框架,他們一般很重、很大、很難學,更要命的是,還不少,什麼Yii二、Thinkphp、CI、ZendFrame、Laravel......好吧我不想說了。windows

另外一種可能composer


如今呢,咱們彷佛有了另一種選擇。依靠composer包管理工具,加載packagist上面那些優秀的組件,而後經過composer提供的自動加載機制,將組建應用到項目中去。咱們的開發彷佛變成了擺積木,咱們要作的事情只是將組件恰當的組合起來,怎麼樣,聽着是否是很心動是麼?全世界優秀的輪子隨我用,這個feel倍爽!!!哦,離題有點遠了,那麼這和本文的主題namespacey又有什麼關係呢?固然有關係了,自動加載的基石namespace框架

實現另一種可能很重要的一步就是,將packagist組件自動加載到應用中。因爲php的_autoload有各類各樣的實現方式,爲此php-fig(php framework interop group一個php組織)提出了psr-0(已經廢棄)和psr-4,這兩個專門自動加載的解決方案,其核心思想就是:將命名空間和實際的磁盤物理路徑創建映射函數

(ps : 到目前爲止spr-0、spr-4只是推薦的自動加載解決方案,並無強制,但事實上,基本都採用了這種自動加載方式。除了spr-和spr-4外,composer還支持file 和classmap的方式)工具

爲何會有命名空間,它解決了什麼問題?

命名空間出現的根本緣由是爲了解決命名衝突的問題,我的認爲主要是爲了解決如下命名衝突性能


  1. 用戶自定義的接口/類/trait/函數/常量 同 php系統提供的 接口/類/trait/函數/常量命名衝突
  2. 用戶自定義的接口/類/trait/函數/常量 同 第三方框架提供的 接口/類/trait/函數/常量命名衝突

舉個例子ui


咱們常用var_dump進行斷點調試,這個是系統提供給咱們的內置函數。可是呢,有的程序員對var_dump輸出的數據格式不是很滿意,但願本身寫一個var_dump函數(var_dump用時間長了,叫其餘的名字不習慣),本身格式化其輸出信息,可是報錯!

<?php
//namespace mydubug;
//若是將上面一行的註釋打開就不會再報錯,只不過調用的時候須要使用mydebug\var_dump的形式了

function var_dump($message)
{
    echo "<br/>========================================</br>"
    echo $message;
    echo "<br/>========================================</br>"
}

/**
 * 報錯信息:PHP Fatal error:  Cannot redeclare var_dump()
 */

命名空間的一些基礎概念?

我將採用類比的方法來講明這些高深的概念,儘可能能讓你們清楚。

全局命名空間


接觸過linux系統的同窗都應該知道根目錄"/"吧,咱們能夠將全局命名空間想象爲linux的根目錄,在該目錄下存放的都是php自己提供的各類接口/類/trait/函數/常量。

徹底限定名稱


以全局命名空間爲前綴的名稱,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();咱們能夠將其類比爲絕對路徑

限定名稱


不以全局命名空間爲前綴的名稱,例如,$a = new subnamespace\foo();或subnamespace\foo::staticmethod();咱們能夠將其類比爲相對路徑

非限定名稱


不包含任何前綴的名稱,例如, $a=new foo(); 或 foo::staticmethod();咱們能夠將其類比一個問文件名稱或者目錄名稱

php中的那些要素會受到命名空間的影響?

首先確定一點,並非全部的元素都受到命名空間的影響,好比說變量就不會,只有如下php要素會受到影響:

  • 類(class)
  • 接口(interface)
  • trait
  • 常量(constant)
  • 方法名(function,我認爲object裏面的方法是method)

什麼是別名/導入?命名空間的解析規則是什麼?二者又有什麼關係?

什麼是別名/導入?

咱們能夠認爲別名/導入,相似是windows下的快捷方式或者是linux下的軟鏈,經過該快捷方式咱們能夠連接到,別的空間下的class、interface、trait、constant、function,甚至能夠是單純的鏈接到別的命名空間而不特指該空間下的任何元素。下面舉個例子

<?php
namespace foo;
use My\Full\Classname as Another;

// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;

$obj = new Another; // 實例化 My\Full\Classname 對象
NSname\subns\func(); // 調用函數 My\Full\NSname\subns\func
?>

當咱們的代碼中有以別名打頭的狀況時,php就會嘗試連接到別名對應的命名空間中的元素,或是別名對應的命名空間,而後拼接剩餘的名稱,若是有的話。例子中NSname\subns\func(); 檢查到NSname是別名,因此先連接到MyFullNSname, 而後拼接剩餘名稱My\Full\NSname\subns\func();

(ps:導入的名稱必須是徹底限定的,不會根據當前的命名空間做相對解析,前導的反斜槓是沒必要要的也不推薦的)

命名空間的解析規則是什麼?

一圖勝千言,仍是上圖吧

clipboard.png

從圖中,能夠看出主要是從徹底限定名和非徹底限定名這兩塊進行分析的。

二者的關係是什麼?

由上圖,咱們能夠知道,限定名稱和非限定名稱的解析都會受到別名的影響。
並且,別名的優先級比當前命名空間的優先級高(不少地方都沒有說)
也就是說,在一個命名空間下,限定名稱和非限定名稱會先嚐試尋找別名替換,若是找不到對應的別名,纔會將當前的命名空間追加到如今的名字前面組成徹底限定名

<?php
//b.php文件
namespace Test\Top;
class B
{
    public function Test()
    {
        echo __FILE__, "\r\n";
    }
}

<?php
//a.php
namespace Top;
use Test\Top as Top;
require __DIR__ . DIRECTORY_SEPARATOR . 'b.php';
Class B
{
    function Test()
    {
        echo __FILE__,"\r\n";
    }
}
(new Top\B())->Test();

a.php和b.php兩個文件在同一個目錄下:在b.php文件中,在namespace Top下面,擁有別名Test\Top as Top,因此new Top\B() 會被解釋成 new Test\Top\B(),也就是將別名進行了替換; 而並非new Top\Top\B(),將當前空間名添加到如今的名字前面。因此此時的運行結果是:xxxx/b.php

命名空間的一些易錯點,僅我的體會

一、class 、interface 、traits和const 、function嘗試執行的加載策略不一樣
clipboard.png

二、一個文件中,只有第一個namespace聲明命名空間前不能有任何字符,特別是bom頭(看不見可是存在),其餘的namespace不作限制。

三、namespace自己並不分區大小寫,相同名字的namespace認爲是同一個空間

<?php
namespace Test{
    function showName()
    {
        echo "This is a test in namespace Test";
    }
}

namespace test{
    function showName()
    {
        echo "This is a test in namespace test";
    }
}
//報錯:PHP Fatal error:  Cannot redeclare test\showName()

參考資料

http://php.net/manual/zh/lang...《Modern php》

相關文章
相關標籤/搜索