溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP類的自動(dòng)加載和命名空間的簡(jiǎn)單介紹

發(fā)布時(shí)間:2021-08-09 23:00:54 來源:億速云 閱讀:150 作者:chen 欄目:編程語(yǔ)言

這篇文章主要介紹“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í)用的文章!

向AI問一下細(xì)節(jié)

免責(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)容。

php
AI