php自動載入

来源:http://www.cnblogs.com/jcuan/archive/2017/04/23/6750534.html
-Advertisement-
Play Games

php自動載入原理 sql_autoload_register PSR-4 ...


php的自動載入

自動載入原理

我們使用另一個文件定義的一個class的時候,傳統的情況下需要require XXX.php

//Good.php
<?php
  class Good{
    //......
  }
 
//use.php
<?php
  require 'Good.php';   //包含進來文件    
  $good = new Good();   //現在可以使用Good類

但是寫require真的很煩!!現在可以使用一個自動載入函數,發現類沒有被定義的時候自動根據我們定義的規則幫我們去require需要的文件。

//Good.php
<?php
  class Good{
    //......
  }

//use.php
<?php
function __autoload($className){
  require $className . '.php';  //定義包含的規則
}

$good = new Good(); //可以使用Good類,發現沒有定義,會自動調用__autoload函數,現在'Good'作為參數傳入了__autoload函數,去包含需要的文件

spl_autoload_register

__autoload函數不能解決所有的問題,現在的項目已經非常複雜,光一個autoload函數已經不能滿足需要了,因為可能不同的模塊使用了不同的自動載入規則。

spl_autoload_register將函數註冊到SPL autoload函數隊列中,它實際上創建了 __autoload 函數的隊列,按定義時的順序逐個執行。相比之下,__ autoload() 只可以定義一次。

函數原型

bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] )
  • autoload_function

欲註冊的自動裝載函數。如果沒有提供任何參數,則自動註冊 autoload 的預設實現函數spl_autoload()。

  • throw

此參數設置了 autoload_function 無法成功註冊時, spl_autoload_register()是否拋出異常。

  • prepend

如果是 true,spl_autoload_register() 會添加函數到隊列之首,而不是隊列尾部。

函數使用

sql_autoload_resister('load_function'); //函數名
sql_autoload_resister(array('load_object', 'load_function')); //類和靜態方法
sql_autoload_resister('load_object::load_function'); //類和方法的靜態調用

//php 5.3之後,也可以像這樣支持匿名函數了。
spl_autoload_register(function($className){
    if (is_file('./lib/' . $className . '.php')) {
        require './lib/' . $className . '.php';
    }
});

note:使用了spl_autoload_register之後原來的__autoload函數就失效了,如果需要繼續使用,需要顯示的註冊它

 if (function_exists('__autoload')) {
   spl_autoload_register('__autoload');
 }

//。。。。。。

 spl_autoload_register('your_autoload_function');   //現在註冊另一個

是否繼續在自動載入函數隊列中查找不取決於載入函數的返回值和是否require了文件,只有真正require需要的文件才會停止


//Good.php位於app文件夾下
<?php
  class Good{
    //......
  }


//Another.php,位於use同級文件夾下
<?php
class Another{
}


//use.php
<?php
function load1($className)
{
    echo "load1\n";
    if (file_exists($className.'.php')) {
        echo 'found: '.$className.PHP_EOL;
        require $className;
    } else {
        echo 'not found: '.$className.PHP_EOL;
    }
}

function load2($className)
{
    echo "load2\n";
    require 'Another.php';
    echo 'require another class'.PHP_EOL;
    return true;
}

function load3($className)
{
    echo "load3\n";
    if (file_exists('app/'.$className.'.php')) {
        echo 'found '.$className.PHP_EOL;
        require 'app/'.$className.'.php';
    } else {
        echo 'not found: '.$className.PHP_EOL;
    }
}


spl_autoload_register('load1');
spl_autoload_register('load2');
spl_autoload_register('load3');

$a = new Good();

輸出如下

load1
not found: Good
load2
require another class
load3
found Good

可以使用spl_autoload_functions()獲得註冊的所有函數

Array
(
    [0] => load1
    [1] => load2
    [2] => load3
)

取消註冊的自動載入函數spl_autoload_unregister

spl_autoload_unregister('load1');

spl_autoload()是__autoload()函數的預設實現

提供了autoload()的一個預設實現。如果不使用任何參數調用 spl_autoload_register() 函數,則以後在進行 autoload() 調用時會自動使用此函數。

自動載入和命名空間

PSR-4自動載入規範

完整的規範請參考PSR-4: Autoloader

標準的類名應該具有下列形式

 \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>

需要強調的:

  • 完整的類名中任意一部分中的下滑線都是沒有特殊含義的
  • 所有類名都必須是大小寫敏感的
  • 所有類名都必須是大小寫敏感的

當根據命名空間載入文件時候:

  • 完整的類名中,去掉最前面的命名空間分隔符,前面連續的一個或多個命名空間和子命名空間,作為“命名空間首碼”,其必須與至少一個“文件基目錄”相對應。
  • 緊接命名空間首碼後的子命名空間必須與相應的”文件基目錄“相匹配,其中的命名空間分隔符將作為目錄分隔符。
  • 末尾的類名必須與對應的以 .php 為尾碼的文件同名。
  • 自動載入器(autoloader)的實現一定不能拋出異常、一定不能觸發任一級別的錯誤信息以及不應該有返回值。

例子

完整類名 命名空間首碼 文件基目錄 文件路徑
\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

實現示例

採用了匿名函數的方式

<?php
/**
 * An example of a project-specific implementation.
 *
 * After registering this autoload function with SPL, the following line
 * would cause the function to attempt to load the \Foo\Bar\Baz\Qux class
 * from /path/to/project/src/Baz/Qux.php:
 *
 *      new \Foo\Bar\Baz\Qux;
 *
 * @param string $class The fully-qualified class name.
 * @return void
 */
spl_autoload_register(function ($class) {
    // project-specific namespace prefix
    $prefix = 'Foo\\Bar\\';

    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/src/';

    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }

    // get the relative class name
    $relative_class = substr($class, $len);

    // replace the namespace prefix with the base directory, replace namespace
    // separators with directory separators in the relative class name, append
    // with .php
    //下邊這一行很關鍵
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }

});

參考資料:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 小分享:我有幾張阿裡雲優惠券,用券購買或者升級阿裡雲相應產品最多可以優惠五折!領券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 在做增刪改查先,先介紹幾個知識點: 1.代理 ...
  • 小分享:我有幾張阿裡雲優惠券,用券購買或者升級阿裡雲相應產品最多可以優惠五折!領券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 這幾天沒更新主要是因為沒有一款合適的後端框架 ...
  • 小分享:我有幾張阿裡雲優惠券,用券購買或者升級阿裡雲相應產品最多可以優惠五折!領券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 前言 上篇博文介紹了怎麼樣在 asp.net ...
  • 小分享:我有幾張阿裡雲優惠券,用券購買或者升級阿裡雲相應產品最多可以優惠五折!領券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 0 Asp.Net Core 項目實戰之許可權 ...
  • 小分享:我有幾張阿裡雲優惠券,用券購買或者升級阿裡雲相應產品最多可以優惠五折!領券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 繼續上一篇《開發 ASP.NET vNext ...
  • ASP.NET MVC動態載入數據,一般的做法是使用$.each方法來迴圈產生tabel:你可以在html時先寫下非動態的部分: <table> <tr> <th style="width:10px;"><input id="SelectAll" type="checkbox" /></th> <t ...
  • 模板語法with關鍵字type u struct { Name string Age int Sex string } user:=&u{Name:"asd",Age:20,Sex:"mal"} data["user"]=user c.HTML(http.StatusOK, "index.html"... ...
  • 最近有個奇葩要求 要項目中的N行代碼 申請專利啥的然後作為程式員當然不能複製粘貼 用代碼解決。。使用python-docx讀寫docx文件環境使用python3.6.0首先pip安裝python-docxpip install python-docx然後下麵是腳本 修改目錄,這裡預設取腳本運行目錄下... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...