1. 程式人生 > >命名空間:不只是代碼封裝

命名空間:不只是代碼封裝

col esp 作用域 輸出 city logs 什麽 space 三種

命名空間

命名空間並不是新事物,在很多面向對象的編程語言中,都得到了很好的支持,它有效的解決了同一個腳本中的成員命名沖突問題。所以說,命名空間是一種代碼封裝技術,代碼中的每個成員,都是自己的活動空間,彼此互不幹擾。
在php中,命名空間主要針對三類成員:函數,常量和類,因為他們三個家夥的作用域都是全局的。所以在同一個腳本中,是不允許重復定義函數,常量和類的。
下面我們用實例來演示:

<?php
const SITE_NAME = ‘PHP中文網‘; //聲明常量SITE_NAME
function sum($n, $m) //聲明函數:sum()
{
return $n+$m;
}
class Staff //
聲明類:Staff { private $name = ‘peter‘; //私有屬性name public function __get($name) //魔術方法__get(),用於外部訪問私有屬性值 { return $this->$name; } public function __set($name, $value) //魔術方法__set(),用於外部更新私有屬性值 { return $this->$name = $value; } } //訪問 echo SITE_NAME; echo ‘<hr>‘; echo sum(10, 20); echo ‘<hr>‘;
echo (new Staff)->name;

現在我們將這三成員,復制一份到下面,這時,當前腳本中就會有二個同名的常量,函數和類了。再次訪問一下,會發生什麽呢?當然會出錯,如果代碼會說話,它肯定會說:嗨,哥們,玩我呢?你究竟要訪問哪個呀?

但是,我現在就是要在同一個腳本中,訪問同名的這三家夥,怎麽呢?好辦:用:用命名空間。
首先,在代碼的第一行,我們寫上 namespce 關鍵字,該關鍵字可以聲明一個命名空間,並且這個關鍵必須必須是代碼的第一行語句,前面不能有任何輸出。
例如,我們將這三個成員的命名空間聲明為:test1;
再把下面與它名稱重復的聲明為:test2,再修改一個test2空間中的SITE_NAME常量的值,類中屬性name的默認值也修改一下,這樣就可以和test1空間的內部區別開了。

<?php
namespace test1;
const SITE_NAME = ‘PHP中文網‘; //聲明常量SITE_NAME
function sum($n, $m) //聲明函數:sum()
{
return $n+$m;
}
class Staff //聲明類:Staff
{
private $name = ‘peter‘; //私有屬性name
public function __get($name) //魔術方法__get(),用於外部訪問私有屬性值
{
return $this->$name;
}
public function __set($name, $value) //魔術方法__set(),用於外部更新私有屬性值
{
return $this->$name = $value;
}
}
namespace test2;
const SITE_NAME = ‘www.php.cn‘;
function sum($n, $m) //聲明函數:sum()
{
return $n+$m;
}
class Staff //聲明類:Staff
{
private $name = ‘jack‘; //私有屬性name
public function __get($name) //魔術方法__get(),用於外部訪問私有屬性值
{
return $this->$name;
}
public function __set($name, $value) //魔術方法__set(),用於外部更新私有屬性值
{
return $this->$name = $value;
}
}
//訪問
echo SITE_NAME;
echo ‘<hr>‘;
echo sum(10, 20);
echo ‘<hr>‘;
echo (new Staff)->name;

好,我們再次訪問一下。發現,沒問題了。為什麽現在就可以了,因為這二段代碼,他們都有自己的有效範圍,這就好比,很多城市,都是一條路:長江路,但我們並不會搞錯,因為這些長江路,盡管路名重復,但是它們屬性不同的城市。

這裏再介紹一個系統魔術常量:__NAMESPCE__,它總是與當前命名空間綁定。
我們現在用這個魔術常量查看一下當前的命名空間是哪個?
echo __NAMESPACE__; //查看當前命名空間
發現當前命名空間是:test2,
現在我想在當前空間test2中,訪問test1中的成員,應該怎麽做呢?
可以這樣訪問:

echo ‘當前命名空間是:‘.__NAMESPACE__;
echo ‘<hr>‘;
echo SITE_NAME; //訪問當前空間中的常量SITE_NAME
echo ‘<hr>‘;
echo \test1\SITE_NAME; //訪問test1空間中的常量SITE_NAME
echo ‘<hr>‘;
echo \test1\sum(40, 50); //訪問test1空間中的函數sum()
echo ‘<hr>‘;
echo sum(10, 20); //訪問當前空間中的函數sum()
echo ‘<hr>‘;
$obj1 = new Staff;
echo $obj1->name; //訪問當前空間中的類實例屬性name
echo ‘<hr>‘;
$obj2 = new \test1\Staff;
$obj2->name = ‘Tom‘; //更新$obj2中的name屬性值
echo $obj2->name; //訪問test1空間中的類實例屬性name

實際開發過程中,在當前空間引入其它空間的成員類型,絕大多數情況,都是類成員,所以php允許使用use關鍵字,在當前空間中引入其它空間的類成員。
我們再次改寫一個代碼:
在test2空間聲明代碼namespace test2後面添加上:
use test1;
use 語句引入命名空間,並不能代替require或include語句,不能自動導入類文件,一定要註意,它只是提供一種命名空間的快捷方式罷了。
另外,use 語句引入命名空間有二個級別:
一是空間級,二是類級。如果是空間級,就是只定位到空間,在訪問時,在類名前還要要加上空間名的,只是不用再加\:全局空間符號了。因為use 默認就是從全局空間開始的。
還有就是類級,直接定位到類上. use test1\Staff類。

其實,現在是有問題的,因為當前空間test2也有一個Staff類,命名沖突了。我們可以通過關鍵as ,給引入的類起個別名來解決: use test1\Staff as test1Staff;

現在訪問:?//訪問

echo ‘當前命名空間是:‘.__NAMESPACE__;
echo ‘<hr>‘;
echo SITE_NAME; //訪問當前空間中的常量SITE_NAME
echo ‘<hr>‘;
echo \test1\SITE_NAME; //訪問test1空間中的常量SITE_NAME
echo ‘<hr>‘;
echo \test1\sum(40, 50); //訪問test1空間中的函數sum()
echo ‘<hr>‘;
echo sum(10, 20); //訪問當前空間中的函數sum()
echo ‘<hr>‘;
$obj1 = new test1Staff;
echo $obj1->name; //訪問當前空間中的類實例屬性name
echo ‘<hr>‘;
$obj2 = new Staff; //僅定位到空間級
// $obj2->name = ‘Tom‘; //更新$obj2中的name屬性值
echo $obj2->name; //訪問test1空間中的類實例屬性name

到現在,我們發現,實際上代碼的運行空間分為二類:一是全局空間,也叫公共空間,在這裏,類,常量,函數等全局成員是不允許重名的。另一類是命名空間,在這個可命名或自定義空間中,這些成員可以與其它空間的成員名稱一樣,並不會沖突。
還有一點:命名空間是可以分層的。就是你文件目錄,有子目錄一樣。
我們來實例演示一下,
在代碼的最下面再寫一個類Demo,它的命名空間是:test2/test3,這就是典型的子空間語法:

namespace test2\test3;
class Demo {
const CITY = ‘合肥‘;
}

同學們,想一下,為什麽要寫代碼的底部,而不直接跟在test2空間的後面寫。
現在在test2空間頂部加上:use test2\test3\Demo;語句,就可以在test2空間使用Demo類了。
現在寫上訪問語句: echo Demo::CITY;

好,到現在為止,我們遇到了三種命名空間的語法:
第一種:從全局空間反斜杠開始寫起,例如 /test1/Staff;這叫:完全限定名稱命名空間。其中全局空間標識符反斜杠不可重命名,與目錄中的絕對路徑很相似。
第二種: 在被訪問成員前加上命名空間標識符:例如: test1/sum(),這叫:限定名稱的命名空間。你可以理解與文件的相對路徑。
第三種:直接訪問空間成員,前面不用加任何空間標識符, 例如 new Staff;這叫:非限定名稱的命名空間,類似於文件當前目錄的概念。

好,命名空間的知識,就講完了,為了教學方便,我把多個命名空間全部寫在一直腳本中,在實際開發中,這不是一個好習慣,應該一個文件,只使用一個命名空間。

命名空間:不只是代碼封裝