新聞中心
php是使用require(require_once)和include(include_once)關(guān)鍵字加載類文件。但是在實(shí)際的開發(fā)工程中我們基本上不會(huì)去使用這些關(guān)鍵字去加載類。 因?yàn)檫@樣做會(huì)使得代碼的維護(hù)相當(dāng)?shù)睦щy。實(shí)際的開發(fā)中我們會(huì)在文件的開始位置用use關(guān)鍵字使用類,然后直接new這個(gè)類就可以了. 至于類是怎么加載的,一般都是框架或者composer去實(shí)現(xiàn)的。
創(chuàng)新互聯(lián)2013年至今,先為西湖等服務(wù)建站,西湖等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為西湖企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
自動(dòng)加載
我們可以通過一段偽代碼來模擬一下在類的實(shí)例化工程中類是如何工作的
function instance($class) { // 如果類已加載則返回其實(shí)例 if (class_exists($class, false)) { return new $class(); } // 查看 autoload 函數(shù)是否被用戶定義 if (function_exists('__autoload')) { __autoload($class); // 最后一次加載類的機(jī)會(huì) } // 再次檢查類是否存在 if (class_exists($class, false)) { return new $class(); } else { // 系統(tǒng):我實(shí)在沒轍了 throw new Exception('Class Not Found'); } }php在語(yǔ)言層面提供了**__autoload** 魔術(shù)方法給用戶來實(shí)現(xiàn)自己的自動(dòng)加載邏輯。當(dāng)用戶去new一個(gè)類的時(shí)候,如果該類沒有被加載,php會(huì)在拋出錯(cuò)誤前調(diào)用**__autoload方法去加載類。下面的例子中的__autoload**方法只是簡(jiǎn)單的輸出要加載類的名稱, 并沒有去實(shí)際的加載對(duì)應(yīng)的類, 所以會(huì)拋出錯(cuò)誤。
運(yùn)行結(jié)果
Illuminate\Container\Container Fatal error: Uncaught Error: Class 'Illuminate\Container\Container' not found in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php:5 Stack trace: #0 {main} thrown in D:\project\php\laravel_for_ci_cd\test\ClassLoader.php on line 5 */明白了 **__autoload** 函數(shù)的工作原理之后,我們來用它去實(shí)現(xiàn)一個(gè)最簡(jiǎn)單自動(dòng)加載。我們會(huì)有index.php和Person.php兩個(gè)文件在同一個(gè)目錄下。
//index.php ' . __CLASS__ . ''; } } /**運(yùn)行結(jié)果 * 輸出Person
*/命名空間
命名空間并不是什么新鮮的事務(wù),很多語(yǔ)言都早就支持了這個(gè)特性(只是叫法不相同),它主要解決的一個(gè)問題就是命名沖突! 就好像日常生活中很多人都會(huì)重名,我們必須要通過一些標(biāo)識(shí)來區(qū)分他們的不同。比如說現(xiàn)在我們要用php介紹一個(gè)叫張三的人 ,他在財(cái)務(wù)部門工作。我們可以這樣描述。
namespace 財(cái)務(wù)部門; class 張三 { function __construct() { echo '財(cái)務(wù)部門的張三'; } }這就是張三的基本資料 , namespace是他的部門標(biāo)識(shí),class是他的名稱. 這樣大家就可以知道他是財(cái)務(wù)部門的張三而不是工程部門的張三。
非限定名稱,限定名稱和完全限定名稱
1.非限定名稱,或不包含前綴的類名稱,例如 $comment = new Comment(); 如果當(dāng)前命名空間是Blog\Article,Comment將被解析為、\Blog\Article\Comment。如果使用Comment的代碼不包含在任何命名空間中的代碼(全局空間中),則Comment會(huì)被解析為\Comment。
注意: 如果文件的開頭有使用use關(guān)鍵字 use one\two\Comment; 則Comment會(huì)被解析為 **one\two\Comment**。
2.限定名稱,或包含前綴的名稱,例如 $comment = new Article\Comment(); 如果當(dāng)前的命名空間是Blog,則Comment會(huì)被解析為\Blog\Article\Comment。如果使用Comment的代碼不包含在任何命名空間中的代碼(全局空間中),則Comment會(huì)被解析為\Article\Comment。
3.完全限定名稱,或包含了全局前綴操作符的名稱,例如 $comment = new \Article\Comment(); 在這種情況下,Comment總是被解析為\Article\Comment。
spl_autoload
接下來讓我們要在含有命名空間的情況下去實(shí)現(xiàn)類的自動(dòng)加載。我們使用 spl_autoload_register() 函數(shù)來實(shí)現(xiàn),這需要你的 PHP 版本號(hào)大于 5.12。spl_autoload_register函數(shù)的功能就是把傳入的函數(shù)(參數(shù)可以為回調(diào)函數(shù)或函數(shù)名稱形式)注冊(cè)到 SPL __autoload 函數(shù)隊(duì)列中,并移除系統(tǒng)默認(rèn)的 **__autoload()** 函數(shù)。一旦調(diào)用 spl_autoload_register() 函數(shù),當(dāng)調(diào)用未定義類時(shí),系統(tǒng)就會(huì)按順序調(diào)用注冊(cè)到 spl_autoload_register() 函數(shù)的所有函數(shù),而**不是自動(dòng)調(diào)用 __autoload()** 函數(shù)。
現(xiàn)在, 我們來創(chuàng)建一個(gè) Linux 類,它使用 os 作為它的命名空間(建議文件名與類名保持一致):
' . __CLASS__ . ''; } }接著,在同一個(gè)目錄下新建一個(gè) index.php文件,使用 spl_autoload_register 以函數(shù)回調(diào)的方式實(shí)現(xiàn)自動(dòng)加載:
文件路徑 'os\\Linux' => './Linux.php', ); /* 根據(jù)類名確定文件路徑 */ $file = $class_map[$class]; /* 引入相關(guān)文件 */ if (file_exists($file)) { include $file; } }); new \os\Linux();這里我們使用了一個(gè)數(shù)組去保存類名與文件路徑的關(guān)系,這樣當(dāng)類名傳入時(shí),自動(dòng)加載器就知道該引入哪個(gè)文件去加載這個(gè)類了。但是一旦文件多起來的話,映射數(shù)組會(huì)變得很長(zhǎng),這樣的話維護(hù)起來會(huì)相當(dāng)麻煩。如果命名能遵守統(tǒng)一的約定,就可以讓自動(dòng)加載器自動(dòng)解析判斷類文件所在的路徑。接下來要介紹的PSR-4 就是一種被廣泛采用的約定方式
PSR-4規(guī)范
PSR-4 是關(guān)于由文件路徑自動(dòng)載入對(duì)應(yīng)類的相關(guān)規(guī)范,規(guī)范規(guī)定了一個(gè)完全限定類名需要具有以下結(jié)構(gòu):
<頂級(jí)命名空間>(<子命名空間>)*<類名>PSR-4 規(guī)范中必須要有一個(gè)頂級(jí)命名空間,它的意義在于表示某一個(gè)特殊的目錄(文件基目錄)。子命名空間代表的是類文件相對(duì)于文件基目錄的這一段路徑(相對(duì)路徑),類名則與文件名保持一致(注意大小寫的區(qū)別)。
舉個(gè)例子:在全限定類名 \app\view\news\Index 中,如果 app 代表 C:\Baidu,那么這個(gè)類的路徑則是 C:\Baidu\view\news\Index.php.我們就以解析 \app\view\news\Index 為例,編寫一個(gè)簡(jiǎn)單的 Demo:
'C:\Baidu', ); /* 解析類名為文件路徑 */ $vendor = substr($class, 0, strpos($class, '\\')); // 取出頂級(jí)命名空間[app] $vendor_dir = $vendor_map[$vendor]; // 文件基目錄[C:\Baidu] $rel_path = dirname(substr($class, strlen($vendor))); // 相對(duì)路徑[/view/news] $file_name = basename($class) . '.php'; // 文件名[Index.php] /* 輸出文件所在路徑 */ echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;以上就是淺析PHP類的自動(dòng)加載和命名空間的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!
文章名稱:PHP中的命名空間和自動(dòng)加載是什么?
文章網(wǎng)址:http://fisionsoft.com.cn/article/gocecs.html