php中的自動加載類機制原理

PHP最先讀取套件的方法php

初學PHP時,最先會面對的問題之一就是require與include差別何在?
require_once與include_once又是什麼?
弄懂這些問題之後,若是不使用framework,直接開發,便常出現類似這樣的code:web

// whatever.php
// 這檔案須要用到幾個類別
require 'xxx_class.php';
require 'yyy_class.php';
require 'zzz_class.php';
// ...

然後在其餘檔案會出現:函數

// another.php
// 這檔案須要用到幾個類別
require 'yyy_class.php';
require 'zzz_class.php';
// ...

這樣的結果,會產生至少兩個問題:
1. 許多檔案用到同樣幾個class,於是在不一樣地方都須要載入一次。
2. 當類別多了起來,會顯得很亂、忘記載入時還會出現error。ui

那麼,不如試試一種懶惰的做法?
寫一個php,負責載入全部類別:code

// load_everything.php
require 'xxx_class.php';
require 'yyy_class.php';
require 'zzz_class.php';
require 'aaa_class.php';
require 'bbb_class.php';
require 'ccc_class.php';

然後在其餘檔案都載入這支檔案便可:io

require 'load_everything.php'

結果新問題又來了:當類別不少的時候,隨便一個web page都會載入一堆code,吃爆記憶體,怎麼辦呢?function

__autoloadclass

為瞭解決這個問題,PHP 5開始提供__autoload這種俗稱「magic method」的函式。
當你要使用的類別PHP找不到時,它會將類別名稱當成字串丟進這個函式,在PHP噴error投降以前,作最後的嘗試:test

// autoload.php
function __autoload($classname) {
    if ($classname === 'xxx.php'){
        $filename = "./". $classname .".php";
        include_once($filename);
    } else if ($classname === 'yyy.php'){
        $filename = "./other_library/". $classname .".php";
        include_once($filename);
    } else if ($classname === 'zzz.php'){
        $filename = "./my_library/". $classname .".php";
        include_once($filename);
    }
    // blah
}

也因為PHP這種「投降前最後一次嘗試」的行為,有時會讓沒注意到的人困惑「奇怪個人code怎麼跑得動?我根本沒有require啊..」,因此被稱為「magic method」。
如此一來,問題彷佛解決了?
惋惜還是有小缺點..,就是這個__autoload函式內容會變得很巨大。以上面的例子來說,一下會去根目錄找、一下會去other_library資料夾、一下會去my_library資料夾尋找。在整理檔案的時候,顯得有些混亂。require

spl_autoload_register

於是PHP從5.1.2開始,多提供了一個函式。
能夠多寫幾個autoload函式,然後註冊起來,效果跟直接使用__autoload相同。
現在能夠針對不一樣用途的類別,分批autoload了。

spl_autoload_register('my_library_loader');
spl_autoload_register('other_library_loader');
spl_autoload_register('basic_loader');

function my_library_loader($classname) {
    $filename = "./my_library/". $classname .".php";
    include_once($filename);
}
function other_library_loader($classname) {
    $filename = "./other_library/". $classname .".php";
    include_once($filename);
}
function basic_loader($classname) {
    $filename = "./". $classname .".php";
    include_once($filename);
}

每個loader內容能夠作不少變化。能夠多寫判斷式讓它更智慧、能夠進行字串處理…。
自動載入類別的問題終於解決了…。

使用spl_autoload_register註冊了自定義的處理器以後,便不會再調用__autoload這個默認的處理器了。這樣作的有點在於:__autoload是一個函數,它只能被定義一次,使用spl_autoload_register能夠把須要在__autoload這一個加載器裏作的事拆分到多個加載器中去分類管理,而且當php須要動態加載類時,spl_autoload_register會按註冊順序依次調用這些加載器來尋找並加載相應的類文件。

另外,註冊到spl_autoload_register裏的處理器方法還能夠是類的靜態方法:

<? 
 
class test {
 public static function loadprint( $class ) {
  $file = $class . '.class.php';  
  if (is_file($file)) {  
   require_once($file);  
  } 
 }
} 
 
spl_autoload_register(  array('test','loadprint')  );
//另外一種寫法:spl_autoload_register(  "test::loadprint"  ); 
 
$obj = new PRINTIT();
$obj->doPrint();
?>
相關文章
相關標籤/搜索