PHP中的命名空間詳細介紹_php技巧

來源:互聯網
上載者:User

概述

PHP對於命名空間的支援,經曆了一段艱難的旅程。幸運的是,PHP從5.3開始引入了命名空間。自從PHP引入了命名空間,PHP代碼的適用結構也得到了大大的改善。許多程式設計語言早就有了命名空間的概念,相對於其他語言來說,PHP對於命名空間的支援,稍微有點晚了。不管如何,每一種新特性的引入都有其目的,和其他語言一樣,PHP引入命名空間也主要是為瞭解決名字衝突的問題。

命名空間(namespace)的概念

複製代碼 代碼如下:

當在字串中使用命名空間名字的時候,一定不要忘了轉義\

可以將命名空間想象成一個抽屜,你可以在抽屜裡放入鉛筆、尺子、A4紙等,這些都是你自己的私人物品。在你的抽屜下面是別人的抽屜,別人也可以在抽屜裡放入相同的物品。為了不拿錯物品,你們決定在自己的抽屜上貼上標籤,這樣就可以清晰的看到某個物品是屬於誰的了。

之前,開發人員必須在類、函數和常量中添加底線,用來使自己的代碼獨立其他於程式碼程式庫。這相當於所有人都給自己的物品貼上標籤之後,一起放入了一個更大的抽屜裡。儘管這也是一種組織代碼的方式,但是這種方式是非常低效的。
命名空間的到來就是為瞭解決這個問題。我們可以在不同的命名空間裡聲明相同的函數、類和常量,而不會造成名字上的衝突。本質上,命名空間無非是一種分等級標記PHP代碼的方式。

正在使用命名空間

有一點需要注意的是,我們正在間接的使用命名空間。從PHP 5.3開始,所有在非使用者定義的命名空間中的聲明(類、函數、常量),都預設的屬於全域命名空間。
全域命名空間中包含了所有PHP內部的定義,如echo()、mysqli_connect()和Exception類。由於全域命名空間並沒有獨立的標識名,所以它經常被成為全域空間(global space)。

定義命名空間

命名空間的定義必須是PHP檔案的第一條語句。唯一允許在定義命名空間之前使用的語句是declare語句。
定義命名空間很簡單,只需要使用關鍵字namespace即可。命名空間的名字需要遵循PHP檔案中其他標識符的命名規則。
下面是定義一個命名空間的樣本:

複製代碼 代碼如下:

namespace MyNamespace{
 class Test{
  
 }
}

如果想定義一個屬於全域空間的代碼塊,也是使用namespace關鍵字,但是後面不加命名空間的名字,如下:

複製代碼 代碼如下:

namespace {
 class Test{
  
 }
}

我們甚至可以在一個檔案中定義多個命名空間,如下:
複製代碼 代碼如下:

<?php
namespace MyNamespace {
}
 
namespace MySecondNamespace {
}
 
namespace {
}

我們也可以將一個命名空間分散在不同的檔案中,檔案包含的處理常式會自動合并他們。因此,限制大量的命名空間在同一個檔案中定義是一個很好的編程實踐,就像我們通常單獨為每個類定義一個單獨的檔案一樣。

複製代碼 代碼如下:

有一點需要注意的是,包含命名空間代碼塊的{是可選的,可以用也可以不用。事實上,只要我們堅持在一個檔案中只定義一個命名空間,那麼我們就可以完全省略{,這樣也可以使我們的代碼看起來更加簡潔。

子命名空間

命名空間可以遵循一個特定的層級,就像我們電腦檔案系統中得目錄一樣。子命名空間對於將一個項目結構化尤其特別有用。例如,你的項目需要訪問資料庫,你可能會想將所有資料庫相關的代碼(如資料庫異常處理等)放在同一個子目錄下。

為了保持靈活性,將子命名空間放在子目錄中是非常明智的做法。這會使你的代碼結構更清晰,而且會使遵循PSR-0標準的autoloaders的使用變得更容易。

PHP使用反斜線\作為命名空間的分隔字元,有趣的是,PHP甚至考慮過使用笑臉:)作為命名空間的分隔字元。

子命名空間定義樣本:

複製代碼 代碼如下:

<?php
namespace MyProject\Database
 
class Connection {
  }

可以使用儘可能多的子命名空間:
複製代碼 代碼如下:

<?php
namespace MyProject\Blog\Auth\Handler\Social;
 
class Twitter {
}

有一點需要注意的是,PHP並不支援命名空間的嵌套定義,下面的代碼會導致一個致命錯誤:Namespace declarations cannot be nested。

複製代碼 代碼如下:

<?php
namespace MyProject {
    namespace Database {
        class Connection { }
    }
}

從命名空間中調用代碼

如果你想在不同的命名空間中執行個體化一個類、調用一個函數或者使用常量,需要使用反斜線\。他們可以從三個角度被解析:

1.未限定的名字
2.限定的名字
3.完整名字

未限定的名字(Unqualified Name)

這是一個類的名稱,函數或常量,但是不包括任何命名的引用。如果命名空間對你來說還比較陌生,那麼這就是你熟悉的角度。

複製代碼 代碼如下:

<?php
namespace MyProject;
 
class MyClass {
    static function static_method()
    {
        echo 'Hello, world!';
    }
}
 
// Unqualified name, resolves to the namespace you are currently in (MyProject\MyClass)
MyClass:static_method();

限定的名字(Qualified Name)

這是我們如何使用子命名空間的方式。樣本如下:

複製代碼 代碼如下:

<?php
namespace MyProject;
 
require 'myproject/database/connection.php';
 
// Qualified name, instantiating a class from a sub-namespace of MyProject
$connection = new Database\Connection();

完整名字(Fully Qualified Name)

前面所說的使用限定的名字和未限定的名字,都是相對於當前所處的命名空間來說的。以上兩種方式僅可以被用來訪問當前所處的命名空間和更深層次的子命名空間。

如果想訪問一個在比前命名空間更高的層級,那麼就需要使用完整名字—一個絕對路徑而不是相對路徑。這可以歸結為在命名空間的最前面加反斜線\。使用完整名字可以讓PHP知道,這次調用是從全域空間開始的,而不是相對於當前所處的命名空間。樣本如下:

複製代碼 代碼如下:

<?php
namespace MyProject\Database;
 
require 'myproject/fileaccess/input.php';
 
// Trying to access the MyProject\FileAccess\Input class
// This time it will work because we use the fully qualified name, note the leading backslash
$input = new \MyProject\FileAccess\Input();

對於PHP的內建函式來說,我們不必要使用完整名字。在當前所處的命名空間中,調用一個不存在的未限定的名字的類或函數,PHP會搜尋全域空間。
記住了這個規則,我們就可以像下面那樣重寫PHP的內建函式:
複製代碼 代碼如下:

<?php
namespace MyProject;
 
var_dump($query); // Overloaded
\var_dump($query); // Internal
 
// We want to access the global Exception class
// The following will not work because there's no class called Exception in the MyProject\Database namespace and unqualified class names do not have a fallback to global space
// throw new Exception('Query failed!');
 
// Instead, we use a single backslash to indicate we want to resolve from global space
throw new \Exception('ailed!');
 
function var_dump() {
    echo 'Overloaded global var_dump()!<br />';
}

動態調用
PHP是一門動態語言,也可以將PHP的這種特性用來調用命名空間。這在本質上與執行個體化一個變數類和包含一個變數檔案是相同的。在字串中,PHP使用的命名空間分隔字元(\)也是一個元字元,因此需要轉義。

複製代碼 代碼如下:

<?php
namespace OtherProject;
 
$project_name = 'MyProject';
$package_name = 'Database';
$class_name = 'Connection';
 
// Include a variable file
require strtolower($project_name . '/'. $package_name .  '/' . $class_name) . '.php';
 
// Name of a variable class in a variable namespace. Note how the backslash is escaped to use it properly
$fully_qualified_name = $project_name . '\\' . $package_name . '\\' . $class_name;
 
$connection = new $fully_qualified_name();

namespace關鍵字
關鍵字namespace不僅僅可以用來定義一個命名空間,它也可以用來顯示的表示當前命名空間,它此時的作用相當於類中的self關鍵字。

複製代碼 代碼如下:

<?php
namespace MyProject;
 
function run()
{
    echo 'Running from a namespace!';
}
 
// Resolves to MyProject\run
run();
// Explicitly resolves to MyProject\run
namespace\run();

__NAMESPACE__常量
就像self關鍵字不能表示當前類的名字一樣,namespace關鍵字也不能用來表示當前命名空間的名字。__NAMESPACE__關鍵字就是用來解決這個問題的。

複製代碼 代碼如下:

<?php
namespace MyProject\Database;
 
// 'MyProject\Database'
echo __NAMESPACE__;

這個關鍵字對於判斷當前代碼是否從命名空間開始時非常有用,而且也可以用來調試代碼。

匯入或別名
PHP中得命名空間也支援匯入,匯入也被成為別名。只有類、介面和命名空間可以被匯入(別名)。匯入是命名空間中一個非常有用和基礎的功能。它使我們可以使用外部的程式碼封裝,而不用擔心名字的衝突。使用use關鍵字可以實現匯入功能。也可以使用as關鍵字,在匯入的時候指定一個別名。

複製代碼 代碼如下:

use [name of class, interface or namespace] as [optional_custom_alias]

一個完整名字可以用一個未限定的別名來代替,這樣我們就不用在每次使用的時候都使用完整名字,達到簡化代碼的目的。匯入應該在命名空間的最高層或者全域空間中使用,在函數範圍內使用匯入功能是非法的文法。

複製代碼 代碼如下:

<?php
namespace OtherProject;
 
// This holds the MyProject\Database namespace with a Connection class in it
require 'myproject/database/connection.php';
 
// If we want to access the database connection of MyProject, we need to use its fully qualified name as we're in a different name space
$connection = new \MyProject\Database\Connection();
 
// Import the Connection class (it works exactly the same with interfaces)
use MyProject\Database\Connection;
 
// Now this works too! Before the Connection class was aliased PHP would not have found an OtherProject\Connection class
$connection = new Connection();
 
// Import the MyProject\Database namespace
use MyProject\Database;
 
$connection = new Database\Connection()

我們可以通過使用別名來簡化上面的代碼:
複製代碼 代碼如下:

<?php
namespace OtherProject;
 
require 'myproject/database/connection.php';
 
use MyProject\Database\Connection as MyConnection;
 
$connection = new MyConnection();
 
use MyProject\Database as MyDatabase;
 
$connection = new MyDatabase\Connection();

總結

命名空間是用來避免定義衝突,並且為代碼引入了更加靈活和組織的方式。有一點需要注意的時,我們並沒有義務去使用命名空間,它是和物件導向結合使用的一種工作方式。但是,如果使用了命名空間,我們的代碼可能會達到一種新的層次,逼格也會顯得更高吧。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.