1. 程式人生 > >淺析PHP類的自動載入和名稱空間

淺析PHP類的自動載入和名稱空間

php是使用require(require_once)和include(include_once)關鍵字載入類檔案。但是在實際的開發工程中我們基本上不會去使用這些關鍵字去載入類。 因為這樣做會使得程式碼的維護相當的困難。實際的開發中我們會在檔案的開始位置用use關鍵字使用類,然後直接new這個類就可以了. 至於類是怎麼載入的,一般都是框架或者composer去實現的。

<?php

use Illuminate\Container\Container;

$container = new Container();

自動載入

我們可以通過一段虛擬碼來模擬一下在類的例項化工程中類是如何工作的

function instance($class)
{
    // 如果類已載入則返回其例項
    if (class_exists($class, false)) {
        return new $class();
    }
    // 檢視 autoload 函式是否被使用者定義
    if (function_exists('__autoload')) {
        __autoload($class); // 最後一次載入類的機會
    }
    // 再次檢查類是否存在
    if (class_exists($class, false)) {
        return new $class();
    } else { // 系統:我實在沒轍了
        throw new Exception('Class Not Found');
    }
}

php在語言層面提供了**__autoload** 魔術方法給使用者來實現自己的自動載入邏輯。當用戶去new一個類的時候,如果該類沒有被載入,php會在丟擲錯誤前呼叫**__autoload方法去載入類。下面的例子中的__autoload**方法只是簡單的輸出要載入類的名稱, 並沒有去實際的載入對應的類, 所以會丟擲錯誤。

<?php

use Illuminate\Container\Container;

$container = new Container();

function __autoload($class)
{
    /* 具體處理邏輯 */
    echo $class;// 簡單的輸出要載入類的名稱
}

/**
 *
執行結果
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** 函式的工作原理之後,我們來用它去實現一個最簡單自動載入。我們會有index.php和Person.php兩個檔案在同一個目錄下。

//index.php
<?php
function __autoload($class)
{
    // 根據類名確定檔名
    $file = './'.$class . '.php';
    if (file_exists($file)) {
        include $file; // 引入PHP檔案
    }
}
new Person();

/*---------------------分割線-------------------------------------*/

//Person.php
class Person
{
    // 物件例項化時輸出當前類名
    function __construct()
    {
        echo '<h1>' . __CLASS__ . '</h1>';
    }
}

/**執行結果
 * 輸出 <h1>Person</h1>
 */

名稱空間

名稱空間並不是什麼新鮮的事務,很多語言都早就支援了這個特性(只是叫法不相同),它主要解決的一個問題就是命名衝突! 就好像日常生活中很多人都會重名,我們必須要通過一些標識來區分他們的不同。比如說現在我們要用php介紹一個叫張三的人 ,他在財務部門工作。我們可以這樣描述。

namespace 財務部門;
 
class 張三
{
    function __construct()
    {
        echo '財務部門的張三';
    }
}

這就是張三的基本資料 , namespace是他的部門標識,class是他的名稱. 這樣大家就可以知道他是財務部門的張三而不是工程部門的張三。

非限定名稱,限定名稱和完全限定名稱

1.非限定名稱,或不包含字首的類名稱,例如 $comment = new Comment(); 如果當前名稱空間是Blog\Article,Comment將被解析為、\Blog\Article\Comment。如果使用Comment的程式碼不包含在任何名稱空間中的程式碼(全域性空間中),則Comment會被解析為\Comment。

注意: 如果檔案的開頭有使用use關鍵字 use one\two\Comment; 則Comment會被解析為 **one\two\Comment**。

2.限定名稱,或包含字首的名稱,例如 $comment = new Article\Comment(); 如果當前的名稱空間是Blog,則Comment會被解析為\Blog\Article\Comment。如果使用Comment的程式碼不包含在任何名稱空間中的程式碼(全域性空間中),則Comment會被解析為\Article\Comment。

3.完全限定名稱,或包含了全域性字首操作符的名稱,例如 $comment = new \Article\Comment(); 在這種情況下,Comment總是被解析為\Article\Comment。

spl_autoload

接下來讓我們要在含有名稱空間的情況下去實現類的自動載入。我們使用 spl_autoload_register() 函式來實現,這需要你的 PHP 版本號大於 5.12。spl_autoload_register函式的功能就是把傳入的函式(引數可以為回撥函式或函式名稱形式)註冊到 SPL __autoload 函式佇列中,並移除系統預設的 **__autoload()** 函式。一旦呼叫 spl_autoload_register() 函式,當呼叫未定義類時,系統就會按順序呼叫註冊到 spl_autoload_register() 函式的所有函式,而**不是自動呼叫 __autoload()** 函式。

現在, 我們來建立一個 Linux 類,它使用 os 作為它的名稱空間(建議檔名與類名保持一致):

<?php
namespace os; // 名稱空間
 
class Linux // 類名
{
    function __construct()
    {
        echo '<h1>' . __CLASS__ . '</h1>';
    }
}

接著,在同一個目錄下新建一個 index.php檔案,使用 spl_autoload_register 以函式回撥的方式實現自動載入:

<?php

spl_autoload_register(function ($class) { // class = os\Linux
 
    /* 限定類名路徑對映 */
    $class_map = array(
        // 限定類名 => 檔案路徑
        'os\\Linux' => './Linux.php',
    );
    /* 根據類名確定檔案路徑 */
    $file = $class_map[$class];
    /* 引入相關檔案 */
    if (file_exists($file)) {
        include $file;
    }
});
 
new \os\Linux();

這裡我們使用了一個數組去儲存類名與檔案路徑的關係,這樣當類名傳入時,自動載入器就知道該引入哪個檔案去載入這個類了。但是一旦檔案多起來的話,對映陣列會變得很長,這樣的話維護起來會相當麻煩。如果命名能遵守統一的約定,就可以讓自動載入器自動解析判斷類檔案所在的路徑。接下來要介紹的PSR-4 就是一種被廣泛採用的約定方式

PSR-4規範

PSR-4 是關於由檔案路徑自動載入對應類的相關規範,規範規定了一個完全限定類名需要具有以下結構:

<頂級名稱空間>(<子名稱空間>)*<類名>

PSR-4 規範中必須要有一個頂級名稱空間,它的意義在於表示某一個特殊的目錄(檔案基目錄)。子名稱空間代表的是類檔案相對於檔案基目錄的這一段路徑(相對路徑),類名則與檔名保持一致(注意大小寫的區別)。

舉個例子:在全限定類名 \app\view\news\Index 中,如果 app 代表 C:\Baidu,那麼這個類的路徑則是 C:\Baidu\view\news\Index.php.我們就以解析 \app\view\news\Index 為例,編寫一個簡單的 Demo:

<?php

$class = 'app\view\news\Index';
 
/* 頂級名稱空間路徑對映 */
$vendor_map = array(
    'app' => 'C:\Baidu',
);
 
/* 解析類名為檔案路徑 */
$vendor = substr($class, 0, strpos($class, '\\')); // 取出頂級名稱空間[app]
$vendor_dir = $vendor_map[$vendor]; // 檔案基目錄[C:\Baidu]
$rel_path = dirname(substr($class, strlen($vendor))); // 相對路徑[/view/news]
$file_name = basename($class) . '.php'; // 檔名[Index.php]
 
/* 輸出檔案所在路徑 */
echo $vendor_dir . $rel_path . DIRECTORY_SEPARATOR . $file_name;

相關推薦

淺析PHP自動載入名稱空間

php是使用require(require_once)和include(include_once)關鍵字載入類檔案。但是在實際的開發工程中我們基本上不會去使用這些關鍵字去載入類。 因為這樣做會使得程式碼的維護相當的困難。實際的開發中我們會在檔案的開始位置用use關鍵字使用類,然後直接new這個類就可以了. 至

PHP自動載入名稱空間及use的理解

今天寫一個demo,遇到一個問題,平時框架用多了,下意識的就以為use就能引入類,導致一直跑不成功,後來才意識到use與引用類並不是一回事。use只是指定了要使用哪個名稱空間下的類,但是並不會引入類,類的引用還是需要使用include或require。這裡記錄一

PHP中的use、名稱空間、引入檔案、自動載入的理解

<div class="postBody"> <div id="cnblogs_post_body" class="cnblogs-markdown"><p>use只是使用了名稱空間,<br>

PHP設計模式:自動載入、PSR-0規範、鏈式操作、11種面向物件設計模式實現使用、OOP的基本原則自動載入配置

一、類自動載入      SPL函式 (standard php librarys)      類自動載入,儘管 __autoload() 函式也能自動載入類和介面,但更建議使用&nbs

十、JAVA多執行緒:JVM載入器(自動載入器、雙親委託機制、載入名稱空間、執行時包、的解除安裝等)

  Jvm提供了三大內建的類載入器,不同的類載入器負責將不同的類載入到記憶體之中 根載入器(Bootstrap ClassLoader) 是最頂層的載入器,是由C++編寫的,主要負責虛擬機器核心類庫的載入,如整個java.lang包,根載入器是獲取不到引用的,因此

分析器錯誤資訊 未能載入型別 名稱空間 ---小結

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

PHP自動載入機制

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

實現 PSR-0PSR-4的自動載入器並帶案例說明

大家在閱讀文件 或者使用一些第三方的框架或者軟體的時候,都聽過或者看過裡面要求說實現了psr0或者psr4的規範。 我也一直在查資料,找痕跡。現在我的理解是,其實這2個規範就是對類的裝載,實現自動尋路徑。 首先我們看下 PSR0 我寫程式碼實現了它的自動載入器 這是載入器程式碼 <

laravel中自動呼叫不用名稱空間的第三方/全域性變數

關於配置 1、找到根目錄下的composer.json檔案 2、找到composer.json中定義的 "autoload": { "classmap": [ "database", "app/Http/util" //在這

分析器錯誤資訊: 未能載入型別"名稱空間."... ---小結

 分析器錯誤資訊: 未能載入型別"名稱空間.類"... 此類問題一般是以下問題引起: 1、。。看看你上次修改程式後,是不是沒有編譯通過?如果沒有編譯通過,修改錯誤的程式碼。 。。.刪除原來的bin及obj下面的dll檔案(刪除該程式生成的dll檔案,引用的dll檔案不要刪除)

Java的裝載器(Class Loader)名稱空間(NameSpace)

摘要 Java的類裝載器是Java動態性的核心,本文將向大家簡要介紹Java的類裝載器,及相關的parent delegation模型,名稱空間,執行時包等概念,同時討論一些在學習中容易混淆的問題。  類裝載器的功能及分類 顧名思義,類裝載器是用來把類(class)裝載進JVM的。JVM規範定義了兩種型別的

分析器錯誤資訊 未能載入型別 名稱空間 ---小結

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!                 分析器錯誤資訊: 未能載入型別"名稱空間.類"... 此類問題一般是以下問題引起:1、。。看看你上次修改程式後,是不是沒有編譯通過?如果沒有編譯通過,修改錯誤

jvm原理(17)載入名稱空間深度解析與例項分析

我們在 上一節講到例項基礎上做一下改動: public class MyTest21 { public static void main(String[] args) throws Exception{ MyTest16 load

載入器 - 名稱空間

本部落格將沿用上篇部落格中展示的自定義類載入器程式碼 複雜類載入情況分析 測試程式碼一 首先,新建一個類Test14,重寫預設的構造方法,列印載入該類的類載入器 public class Test14 { public Test14() { System.out.println(&

PHP 型判斷NULL,空值檢查

ron cal 簡單 www its 類型 cti 哪些 是否 PHP是一種寬松類型的編程語言,在函數中對傳入的參數值的“類型”以及”值是否為空或者NULL“進行檢查是不可缺少的步驟。 類型檢查 從PHP

一段程式碼看懂Java載入初始化

先貼程式碼 class Base { int a = numa(); private static int c = numc(); static int b = numb(); static { System.out.println("Base:static code b

C++PrimerPlus學習之記憶體模型名稱空間

標頭檔案 如果檔名包含在尖括號中,則C++編譯器將在儲存標準標頭檔案的主機系統的檔案系統的中查詢。如果檔名包含在雙引號中,則編譯器將在當前目錄下查詢。 使用條件編譯防止多次包含標頭檔案 #ifndef XXX_H_ #define XXX_H_ ... #en

PHP動態訪問元素時名稱空間的使用

受PHP自身的動態特徵的影響,在動態訪問元素時,必須使用完全限定名,所以在動態的類、函式或常量名稱中,限定名稱和完全限定名沒有區別,都是按照完全限定名進行解析。 <?php namespace { const con=0; const test="test"; function fo

01_Docker概念簡介、元件介紹、使用場景名稱空間

一、簡介 Docker是一個能夠把開發的應用程式自動部署到容器的開源引擎。Docker在虛擬化的容器執行環境中增加了一個應用程式部署引擎。該引擎的目標就是提供一個輕量、快速的環境,能夠執行開發者的程式,並方便高效地將程式從開發者的筆記本部署到測試環境,然後再部署到生產環境。Docker極其簡潔,它所需的全部

動態傳參(*args **kwargs 無敵傳參) 作用域globals locals名稱空間 函式的巢狀 關鍵字nonlcas global

動態傳參(重點) *, ***, ** :形參: 聚合 位置引數* -> 元組 關鍵字** -> 字典實參: 打散 列表, 字串, 元素 -> * 字典 -> ** 形參的順序(重點): 位置 *args(位置引數動態傳參) 預設值 **kwargs