濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > PHP自動(dòng)加載機(jī)制實(shí)例詳解

PHP自動(dòng)加載機(jī)制實(shí)例詳解

熱門(mén)標(biāo)簽:沈陽(yáng)人工智能電銷(xiāo)機(jī)器人公司 h5 地圖標(biāo)注 電銷(xiāo)機(jī)器人-快迭智能 高識(shí)別電銷(xiāo)機(jī)器人 哈爾濱400電話辦理到易號(hào)網(wǎng) 拉薩打電話機(jī)器人 智能外呼電銷(xiāo)系統(tǒng) 寶安400電話辦理 合肥外呼系統(tǒng)app

本文實(shí)例講述了PHP自動(dòng)加載機(jī)制。分享給大家供大家參考,具體如下:

在php中,我們一般使用 require, requre_once, include, include_once 這四個(gè)命令來(lái)加載其他php文件,這在一般小型的php文件中是沒(méi)有任何問(wèn)題的,相信每個(gè)初學(xué)者都會(huì)遇到這樣的應(yīng)用場(chǎng)景:使用一個(gè) Db.php 來(lái)定義數(shù)據(jù)庫(kù)連接,在其他文件中直接引用這個(gè)文件,達(dá)到代碼復(fù)用的效果。

再讓我們考慮這樣一個(gè)應(yīng)用場(chǎng)景,如果我們使用一個(gè)框架,或者一個(gè)第三方包,里面一般有成百上千個(gè)類(lèi)文件,而我們通常是不用自己去加載這些文件的,此時(shí)用的便是php的自動(dòng)加載機(jī)制。

定義一種自動(dòng)加載模式

在傳統(tǒng)的應(yīng)用中,通常自定義 __autoload()。如下

define("DIR", "/var/www/myWeb/myClass/");
function __autoload($classname) {
  require DIR.$classname.'.class.php';
}
$book = new Book();

上述代碼運(yùn)作過(guò)程如下:

1. 自定義 __autoload 函數(shù),它定義了類(lèi)文件的加載方式
2. 當(dāng)我們 new 一個(gè) Book 實(shí)例時(shí),它首先看當(dāng)前是否包含了這個(gè)類(lèi),如果不存在則自動(dòng)調(diào)用 __autoload 函數(shù)并將類(lèi)名 Book 作為參數(shù)傳遞給這個(gè)函數(shù)。這實(shí)際上就是一種動(dòng)態(tài)加載的方式,只有我們需要的類(lèi)文件才會(huì)被加載。
3. 找到 __autoload 函數(shù)后,發(fā)現(xiàn)定義好的加載動(dòng)作 require DIR.$classname.'.class.php'; 這時(shí)候它就會(huì)去 DIR 目錄下查找 Book.class.php 文件,如果存在這個(gè)文件則加載。
4. 關(guān)于類(lèi) Book.class.php 的定義必須滿(mǎn)足如下條件:類(lèi)名和文件名一致;一個(gè)文件只定義一個(gè)類(lèi)。

Book.class.php 文件如下

class Book {
  public function __construct() {
    echo "this is Book's construct\n";
  }
}

注冊(cè)多種加載模式

對(duì)于我們自己的簡(jiǎn)單應(yīng)用,一種加載模式可能夠用了,但是對(duì)于較大型的應(yīng)用,上面的方式存在明顯的缺陷:__autoload函數(shù)不能重復(fù)定義,也就是說(shuō)我們只能定義一種加載文件的模式,最終的結(jié)果就是我們的類(lèi)只能放在一個(gè)地方,這顯然是不符合實(shí)際要求的。因此php使用了函數(shù) spl_autoload_register 來(lái)代替 __autolaod

代碼如下:

define("MODEL_DIR", "/var/www/myWeb/myModel/");
define("CONTROLLER_DIR", "/var/www/myWeb/myController/");
// 定義Model類(lèi)加載方式
function loadModel($classname) {
  $filename = MODEL_DIR.$classname.'.php';
  if (file_exists($filename))
    require $filename;
}
// 定義Controller加載方式
function loadController($classname) {
  $filename = CONTROLLER_DIR.$classname.'.php';
  if (file_exists($filename))
    require $filename;
}
// 注冊(cè)兩個(gè)加載函數(shù)
spl_autoload_register("loadModel");
spl_autoload_register("loadController");
// 自動(dòng)加載類(lèi)文件
$bookMode = new BookMode();
$bookController = new BookController();

在上面的代碼中,我們可以看到:

1. 可以使用任意函數(shù)名定義多個(gè)加載函數(shù)
2. 在 spl_autoload_register 對(duì)加載函數(shù)進(jìn)行注冊(cè),實(shí)際上應(yīng)該是添加到一個(gè)類(lèi)似雙向隊(duì)列的數(shù)據(jù)結(jié)構(gòu)中。
3. 當(dāng)我們 new 的對(duì)象不存在于當(dāng)前文件時(shí),它會(huì)自動(dòng)從我們的加載函數(shù)中查找,并且是按照我們使用 spl_autoload_register 注冊(cè)的順序進(jìn)行的。
4. 需要注意的是,此時(shí)如果我們定義了 __autoload 方法,也必須進(jìn)行注冊(cè),否則會(huì)被忽略。

spl_autoload_register三種注冊(cè)函數(shù)的方式:

spl_autoload_register(funName); // 直接注冊(cè)一個(gè)普通加載函數(shù)
spl_autoload_register(obj::method); // 注冊(cè)一個(gè)靜態(tài)加載方法
spl_autoload_regitser(array(obj, method)); // 當(dāng)obj為類(lèi)字符串時(shí),只能加載靜態(tài)方法。否則都可以。

實(shí)例

在各種php框架中,也大量用到了自動(dòng)加載機(jī)制,我們通過(guò)laravel的一個(gè)小例子來(lái)看下。

laravel通過(guò) Ioc 容器幫我們管理依賴(lài),讓我們可以通過(guò)函數(shù)參數(shù)的方式愉快地獲得了類(lèi)實(shí)例,但我們也發(fā)現(xiàn),我們并沒(méi)有require文件,那容器又是如何找到我們的文件地址的?下面我們就來(lái)解決這個(gè)問(wèn)題。

通過(guò)入口文件 index.php 我們一步步搜索,可以找到 /vendor/composer/ClassLoader.php 文件。

部分代碼如下

public static function loadClassLoader($class)
{
  if ('Composer\Autoload\ClassLoader' === $class) {
    require __DIR__ . '/ClassLoader.php';
  }
}
public static function getLoader()
{
  if (null !== self::$loader) {
    return self::$loader;
  }
  spl_autoload_register(array('obj', 'loadClassLoader'), true, true);
  // 通過(guò)命名空間的方式使用注冊(cè)的加載類(lèi)
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
  spl_autoload_unregister(array('obj', 'loadClassLoader'));
  if (PHP_VERSION_ID >= 50600) {
    // 該文件定義了包類(lèi)和用戶(hù)類(lèi)的命名空間和實(shí)體文件的映射
    // 以及其他一些東西
    require_once __DIR__ . '/autoload_static.php';
    // 初始化$loader一些屬性。
    // 我們關(guān)注autoload_static.php文件的類(lèi)映射
    // 被賦值在了 $loader的$classMap屬性
        call_user_func(\Composer\Autoload\ComposerStaticInit::getInitializer($loader));
    // ...
  }
  // ...
  $loader->register(true);
  // ...
  return $loader;
}

它調(diào)用了 getLoader() 函數(shù),并將 loadClassLoader 函數(shù)注冊(cè)到加載函數(shù)注冊(cè)隊(duì)列。然后就可以通過(guò)命名空間的方式 self::$loader = $loader = new \Composer\Autoload\ClassLoader(); 實(shí)例化 ClassLoader 類(lèi)。

緊接著,他載入了 /autoload_static.php 文件,大致內(nèi)容如下

// 里面還定義了包類(lèi)和psr的一些標(biāo)準(zhǔn)
public static $classMap = array (
  'App\\Common\\Collection' => __DIR__ . '/../..' . '/app/Common/Collection.php',
  'App\\Common\\MgDB' => __DIR__ . '/../..' . '/app/Common/MgDB.php',
  'App\\Common\\Redis' => __DIR__ . '/../..' . '/app/Common/Redis.php',
)

看到這里筆者興奮了,因?yàn)樯厦娴?Collection, Redis 正是筆者定義的類(lèi)!
然后就是我們?cè)趌aravel經(jīng)常聽(tīng)到的一個(gè)名詞 “register”。查看 ClassLoader 類(lèi)的 register 方法如下:

public function register($prepend = false)
{
  spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
public function loadClass($class)
{
  if ($file = $this->findFile($class)) {
    includeFile($file);
    return true;
  }
}
public function findFile($class)
{
  // ...
  // class map lookup
  if (isset($this->classMap[$class])) {
    return $this->classMap[$class];
  }
  // ...
}

上面的register方法同樣使用了自動(dòng)加載機(jī)制。并將通過(guò)findFile函數(shù)和$classMap數(shù)組直接找到對(duì)應(yīng)的類(lèi)的具體位置。這也就是我們不用自己去加載類(lèi)文件的原因 – 當(dāng)我們實(shí)例化一個(gè)代碼中找不到的類(lèi)時(shí),它便會(huì)在這里加載對(duì)應(yīng)的類(lèi)。

看到這里我們也發(fā)現(xiàn)了它的使用和我們之前講的并不完全一致,我們是注冊(cè)函數(shù)是為了通過(guò)文件夾來(lái)尋找類(lèi),而laravel注冊(cè)函數(shù)是為了注冊(cè)一個(gè)映射數(shù)組然后直接調(diào)用(整了個(gè)映射文件三千多行。。。)具體為什么要這么做得等下次通讀加載源碼部分后再寫(xiě)一篇博文(本來(lái)只想找一個(gè)框架的例子,蜜汁尷尬)

筆者實(shí)例

兩年前負(fù)責(zé)學(xué)校某個(gè)協(xié)會(huì)線上部分時(shí),主要是做微信開(kāi)發(fā),因?yàn)闀r(shí)不時(shí)就要加一個(gè)新功能,所以如果用一般的方式寫(xiě)起來(lái)是比較痛苦的,但是用框架又有點(diǎn)大材小用。因?yàn)榫褪褂昧讼旅孢@種簡(jiǎn)單的方式:

require "./basic/init.php";
define('WEB_PATH', '');
//聲明自動(dòng)加載函數(shù)并注冊(cè),指示加載路徑與加載方法
  function wechatAutoload($class_name)
  {
    $file_road = './function/'.$class_name.'.class.php';
    if(file_exists($file_road))
    {
      require_once($file_road);
    }
  }
  spl_autoload_register('wechatAutoload');
//----------------------------------------------

初始化好配置之后,我們注冊(cè)了一個(gè)加載函數(shù),以后每一個(gè)新功能都只要在 function 文件夾下新增一個(gè)文件即可,其他部分的改動(dòng)很少或者根本不用(根據(jù)業(yè)務(wù)場(chǎng)景)。

參考:PHP: spl_autoload_register - Manual

更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》、《PHP數(shù)組(Array)操作技巧大全》、《PHP基本語(yǔ)法入門(mén)教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門(mén)教程》及《php常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》

希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。

您可能感興趣的文章:
  • 說(shuō)說(shuō)PHP的autoLoad自動(dòng)加載機(jī)制
  • PHP的autoload自動(dòng)加載機(jī)制使用說(shuō)明
  • PHP autoload與spl_autoload自動(dòng)加載機(jī)制的深入理解
  • PHP面向?qū)ο笞詣?dòng)加載機(jī)制原理與用法分析
  • thinkPHP5.0框架自動(dòng)加載機(jī)制分析
  • php自動(dòng)加載機(jī)制的深入分析
  • php _autoload自動(dòng)加載類(lèi)與機(jī)制分析
  • php自動(dòng)加載autoload機(jī)制示例分享

標(biāo)簽:梅州 山東 泰州 威海 巴中 成都 林芝 張家口

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《PHP自動(dòng)加載機(jī)制實(shí)例詳解》,本文關(guān)鍵詞  PHP,自動(dòng),加載,機(jī)制,實(shí)例,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《PHP自動(dòng)加載機(jī)制實(shí)例詳解》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于PHP自動(dòng)加載機(jī)制實(shí)例詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    昌吉市| 巴林左旗| 安塞县| 白城市| 乐亭县| 阿拉善盟| 江油市| 鹰潭市| 保定市| 民乐县| 麻城市| 射阳县| 个旧市| 政和县| 清原| 永定县| 松江区| 洪雅县| 股票| 夏津县| 桐柏县| 工布江达县| 凉城县| 丹阳市| 岱山县| 阜阳市| 拜泉县| 措美县| 新源县| 巴青县| 汽车| 商南县| 龙里县| 潜江市| 芮城县| 奉新县| 汨罗市| 双流县| 鱼台县| 定安县| 嘉禾县|