您好,登錄后才能下訂單哦!
這篇文章主要介紹“PHP類的自動(dòng)加載和命名空間的簡(jiǎn)單介紹”,在日常操作中,相信很多人在PHP類的自動(dòng)加載和命名空間的簡(jiǎn)單介紹問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”PHP類的自動(dòng)加載和命名空間的簡(jiǎn)單介紹”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
淺析PHP類的自動(dòng)加載和命名空間
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)的。
<?php use Illuminate\Container\Container; $container = new Container();
自動(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ò)誤。
<?php use Illuminate\Container\Container; $container = new Container(); function __autoload($class) { /* 具體處理邏輯 */ echo $class;// 簡(jiǎn)單的輸出要加載類的名稱 } /** *
運(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 <?php function __autoload($class) { // 根據(jù)類名確定文件名 $file = './'.$class . '.php'; if (file_exists($file)) { include $file; // 引入PHP文件 } } new Person(); /*---------------------分割線-------------------------------------*/ //Person.php class Person { // 對(duì)象實(shí)例化時(shí)輸出當(dāng)前類名 function __construct() { echo '<h2>' . __CLASS__ . '</h2>'; } } /**運(yùn)行結(jié)果 * 輸出 <h2>Person</h2> */
命名空間
命名空間并不是什么新鮮的事務(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 作為它的命名空間(建議文件名與類名保持一致):
<?php namespace os; // 命名空間 class Linux // 類名 { function __construct() { echo '<h2>' . __CLASS__ . '</h2>'; } }
接著,在同一個(gè)目錄下新建一個(gè) index.php文件,使用 spl_autoload_register 以函數(shù)回調(diào)的方式實(shí)現(xiàn)自動(dòng)加載:
<?php spl_autoload_register(function ($class) { // class = os\Linux /* 限定類名路徑映射 */ $class_map = array( // 限定類名 => 文件路徑 '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:
<?php $class = 'app\view\news\Index'; /* 頂級(jí)命名空間路徑映射 */ $vendor_map = array( 'app' => '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;
到此,關(guān)于“PHP類的自動(dòng)加載和命名空間的簡(jiǎn)單介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。