PHP中的命名空間

Note:
名爲PHP或php的命名空間,以及以這些名字開頭的命名空間(例如PHP\Classes)被保留用做語言內核使用,而不該該在用戶空間的代碼中使用php

定義命名空間

定義: 經過namespace關鍵字聲明函數

子名命名空間:與目錄和文件的關係很像,PHP名命空間容許指定層次化的命名空間名稱,這種使用分層次的方式定義的命名空間被稱爲子命名空間。編碼

//定義命名空間
<?php
//declare(encoding='UTF-8');    //  namespace定義前面惟一合法語句,不是必須
namespace MyProject;
……
?>

//定義子命名空間
<?php
namespace MyProject\Sub\Level;
……
?>

說明:spa

  1. 任意合法PHP代碼均可以包含在命名空間中,但只有如下類型的代碼受命名空間的影響:類(包括抽象類和traits)接口函數常量
  2. 同一個命名空間能夠定義在多個文件中,即容許將同一個命名空間的內容分割存放在不一樣的文件中。

注意事項: 若是一個文件中包含命名空間,它必須在全部代碼以前聲明命名空間,在聲明命名空間以前惟一合法的代碼是用於定義源文件編碼方式的declare語句,另外,全部非PHP代碼包括空白符都不能出如今命名空間的聲明以前。.net

在同一個文件中定義多個名命空間(不提倡,這種方式主要用於將多個PHP腳本合併在同一個文件中 )

定義方式有兩種:code

  • 簡單組合語法
<?php
namespace MyProject;
代碼段……

namespace AnotherProject;
代碼段……
?>
  • 大括號語法
<?php
namespace MyProject{
    代碼段……
}

namespace AnotherProject{
    代碼段……
}
?>

若是是將全局的非命名空間中的代碼與名命空間中的代碼組合在一塊兒,則只能使用大括號形式的語法。全局代碼必須用一個不帶名稱的namespace語句加上大括號括起來:對象

<?php
namespace MyProject{
    代碼段……
}

namespace{      //全局空間
    代碼段……
}
?>

注意: 除了開始的declare語句外,命名空間的括號外不得有任何PHP代碼。接口

使用名命空間:基礎

(PHP 5 >= 5.3.0, PHP 7)字符串

在討論如何使用命名空間以前,必須瞭解 PHP 是如何知道要使用哪個命名空間中的元素的。能夠將 PHP 命名空間與文件系統做一個簡單的類比。get

在文件系統中訪問一個文件有三種方式:
  1. 相對文件名形式,如foo.txt。它會被解析爲 currentdirectory/foo.txt,其中 currentdirectory 表示當前目錄。所以若是當前目錄是 /home/foo,則該文件名被解析爲/home/foo/foo.txt。
  2. 相對路徑名形式如subdirectory/foo.txt。它會被解析爲 currentdirectory/subdirectory/foo.txt。
  3. 絕對路徑名形式如/main/foo.txt。它會被解析爲/main/foo.txt。
PHP 命名空間中的元素使用一樣的原理。例如,類名能夠經過三種方式引用:
  1. 非限定名稱,或不包含前綴的類名稱,例如 $a=new foo(); 或 foo::staticmethod();。若是當前命名空間是 currentnamespace,foo 將被解析爲 currentnamespace\foo。若是使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,則 foo 會被解析爲foo。

備註: 若是命名空間中的函數或常量未定義,則該非限定的函數名稱或常量名稱會被解析爲全局函數名稱或常量名稱。即:若是在當前命名空間中沒有找到函數或常量,則接着會嘗試去全局空間中找。若是仍未找到,則此時會報錯。,若是類沒有在當前命名空間中定義,則不會去全局空間找。詳情參見 使用命名空間:後備全局函數名稱/常量名稱一節。

  1. 限定名稱,或包含前綴的名稱,例如 $a = new subnamespace\foo(); 或 subnamespace\foo::staticmethod();。若是當前的命名空間是 currentnamespace,則 foo 會被解析爲 currentnamespace\subnamespace\foo。若是使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,foo 會被解析爲subnamespace\foo。
  1. 徹底限定名稱,或包含了全局前綴操做符的名稱,例如, $a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在這種狀況下,foo 老是被解析爲代碼中的文字名(literal name)currentnamespace\foo。

示例:

file1.php

<?php
namespace Foo\Bar\subnamespace;
const FOO=1;
function foo(){}
class foo{
    static function staticmethod(){}
}
?>

file2.php

<?php
namespace Foo\Bar;
include 'file1.php';

const FOO = 2;
function foo() {}
class foo
{
    static function staticmethod() {}
}

/* 非限定名稱 */
foo();                  // 解析爲 Foo\Bar\foo 
foo::staticmethod();    // 解析爲類 Foo\Bar\foo的靜態方法staticmethod。
echo FOO;               // 解析爲 Foo\Bar\FOO

/* 限定名稱 */
subnamespace\foo();                 // 解析爲函數 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod();   // 解析爲類 Foo\Bar\subnamespace\foo,以及類的方法 staticmethod
echo subnamespace\FOO;              // 解析爲常量 Foo\Bar\subnamespace\FOO
                                  
/* 徹底限定名稱 */
\Foo\Bar\foo();                      // 解析爲函數 Foo\Bar\foo
\Foo\Bar\foo::staticmethod();       // 解析爲類 Foo\Bar\foo, 以及類的方法 staticmethod
echo \Foo\Bar\FOO;                  // 解析爲常量 Foo\Bar\FOO
?>

注意: 訪問任意全局類、函數或常量,均可以使用徹底限定名稱,例如:\strlen()\Exception\INI_ALL

命名空間和動態語言特徵

說明: 名命空間的實現會受到其語言自身的動態特徵的影響。在使用動態的類名稱、函數名稱、常量名稱時,須要使用【徹底】限定名稱。

注意: 由於在動態的類名稱、函數名稱、常量名稱中,限定名稱和徹底限定名稱沒有區別,所以,其前導的反斜槓是沒必要要的。

<?php

namespace{
    class classname{
        function __construct(){
            echo __METHOD__,"<br>";
        }
    }

    function funcname(){
        echo __FUNCTION__,"<br>";
    }

    const constname = "global";

    $a = 'classname';
    $obj = new $a;                          //打印 classname::__construct
    $b = 'funcname';
    $b(); // prints funcname
    echo constant('constname'), "<br>";     //打印 prints global
    }


namespace namespacename{
    class classname{
        function __construct(){
            echo __METHOD__,"<br>";
        }
    }

    function funcname(){
        echo __FUNCTION__,"<br>";
    }

    const constname = "namespaced";

    $a = 'classname';
    $obj = new $a;                          //打印 classname::__construct
    $b = 'funcname';
    $b(); // prints funcname
    echo constant('constname'), "<br>";     //打印 global
    
    echo '<hr>';
    
    $a = '\namespacename\classname';
    $obj = new $a;      //打印 namespacename\classname::__construct
    $a = 'namespacename\classname';
    $obj = new $a;      //打印 namespacename\classname::__construct
    $b = 'namespacename\funcname';
    $b();               //打印 namespacename\funcname
    $b = '\namespacename\funcname';
    $b();               //打印 namespacename\funcname
    echo constant('\namespacename\constname'), "<br>";  // 打印 namespaced
    echo constant('namespacename\constname'), "<br>";   // 打印 namespaced
}
?>

namespace關鍵字和__NAMESPACE__常量

PHP支持兩種抽象的訪問當前命名空間內部的方法:

1. __NAMESPACE__魔術常量

返回值: 包含當前名命空間名稱的字符串。在全局的,不包括在任何命名空間中的代碼,它返回一個空字符串

該常量在動態建立類時頗有用:

<?php
    namespace MyProject;
    function get($classname){
        $a=__NAMESPACE__.'\\'.$classname;
        return new $a;
    }
    ?>

2. namespace關鍵字

做用: 用來顯式訪問當前名命空間或子名命空間中的元素。它等價於類中的self操做符

名命空間中的代碼

<?php
    namespace MyProject;
    use blah\blah as mine;
    blah\mine();    //Myproject\blah\mine()
    namespace\blah\mine();  //MyProject\blah\mine
    
    namespace\func();       //MyProject\func()
    namespace\sub\func();   //MyProject\sub\func()
    namaspace\cname::method();  MyProject\cname::method()
    $a=new namespace\sub\cname();   //MyProject\sub\cname
    $b=namespace\CONSTANT;  //MyProject\CONSTANT
    ?>

全局代碼

<?php
namespace\func();               //func()
namespace\sub\func();           //sub\func()
namespace\cname::method();      //cname::method()
$a=new namespace\sub\cname();   //sub\cname
$b=namespace\CONSTANT;          //CONSTANT

使用命名空間:別名/導入

PHP容許經過別名應用或導入外部的徹底限定名稱。

全部支持名命空間的PHP版本都支持三種別名或導入方式:

  • 爲類名稱使用別名
  • 爲接口使用別名
  • 爲名命空間使用別名

PHP5.6開始容許導入函數常量或者爲它們設置別名

導入關鍵字:use

  • 爲了簡化操做,PHP支持在一行中使用多個use語句,中間用‘,’隔開。

特別說明: 對命名空間中的名稱(包含命名空間分隔符的徹底限定名稱)來講,前導的反斜槓是沒必要要的也是不推薦的,由於導入的名稱必須是徹底限定的,不會根據當前的名命空間做相對解析。

如下說的意思算是對上面內容的解釋吧:

  1. 導入操做是在編譯執行的,但動態的類名稱、函數名稱或常量名稱則不是。(大概是說,導入是在編譯期執行,而實際代碼中的動態名稱是在執行時肯定)

  2. 導入操做隻影響非限定名稱和限定名稱。徹底限定名稱因爲是肯定的,故不受導入的影響。(大概是說,use 語句引用的時候都是徹底限定名稱,而實際代碼中使用過的時候要注意非限定名稱、限定名稱和徹底限定名稱的使用)

兩個示例:

導入和動態名稱:

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 實例化一個 My\Full\Classname 對象
$a = 'Another';
$obj = new $a;      // 實際化一個 Another 對象
?>

導入和徹底限定名稱

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>

使用命名空間:後備全局函數/常量

重要: 在一個命名空間中,當 PHP 遇到一個非限定的類、函數或常量名稱時,它使用不一樣的優先策略來解析該名稱。類名稱老是解析到當前命名空間中的名稱。所以在訪問系統內部或不包含在命名空間中的類名稱時,必須使用徹底限定名稱。 對於函數和常量來講,若是當前命名空間中不存在該函數或常量,PHP 會退而使用全局空間中的函數或常量

相關文章
相關標籤/搜索