5.2 自動加載
在一個文件里使用一個類,我們可以用include、require來引入類文件。
例如,Cat類定義在cat.php文件里,請看示例代碼:(源碼文件:ch05/autoload/require/cat.php)

在test.php里使用Cat類,可以使用include、require函數引入cat.php文件。程序實現如下:(源碼文件:ch05/autoload/require/test.php)
<?php require './cat.php'; //require_once './cat.php'; //include './cat.php'; //include_once './cat.php'; $tom = new Cat(); $tom->eat(); //Output cat eat fish
但如果需要引入多個文件,使用引入函數就非常低效了:
require './cat.php'; require './dog.php'; require './monkey.php'; require './elephant.php';
為了解決自動加載的問題,PHP提供了三種解決方案:__autoload、spl_autoload和spl_autoload。
5.2.1 __autoload
__autoload是魔術方法,當調用未定義的類時,_autoload()會被調用,用于按照規則加載未定義的類。
__autoload定義如下:
void __autoload ( string $class )
參數是要調用的類名。實現__autoload方法的一般步驟如下:
步驟01 由類名找到對應的文件名。
步驟02 判斷文件是否存在。
步驟03 用include、require等函數引入文件。
為了說明__autoload的使用方法,我們編寫了一個示例,請查看autoload/autoload目錄。
示例中的文件結構如下:
cat.php dog.php monkey.php test.php
我們在調用時,不使用引入函數,直接實現__autoload方法。上面的目錄結構比較簡單,文件名是類名的小寫形式,路徑在當前目錄下查找。
程序實現代碼如下:(源碼文件:ch05/autoload/autoload/test.php)

需要注意的是,__autoload在PHP 7.2.0中已被廢棄。
__autoload不能重復定義,只能注冊一個,這在協作項目或需要引入多個第三方包時,變得非常不方便。所以PHP引入spl_autoload_register來解決這個問題。
5.2.2 spl_autoload_register
為了解決多個自動加載函數的問題,PHP引入了spl_autoload_register函數。其定義如下:

為了說明__autoload的使用方法,我們編寫了一個示例,請查看autoload/spl_autoload_register目錄。
示例中的文件結構如下:

由于表示動物的類分成大型動物(big_animal)和小型動物(small_animal),所以需要兩個加載函數:

spl_autoload_register允許多個加載函數,是非常有用的一個功能。如果從composer安裝一個第三方包,那個包可以自行處理自動加載,而作為使用者無須關心。這使得協作和開源變得更加便利。
關于__autoload與spl_autoload_register的比較如表5-2所示。
表5-2 __autoload與spl_autoload_register的比較

5.2.3 spl_autoload
spl_autoload是__autoload的一個默認實現,當spl_autoload_register無參數時默認調用。其實現的功能為在include路徑里查找類。
以下是一個使用示例:

可以看到,spl_autoload只能設置路徑和文件后綴,所以在實際項目中應用較少,屬于雞肋功能。
5.2.4 面試題:引用文件函數的區別
題目描述1:include、require、inclue_once、require_once有什么區別?
解答:include和require的區別是當引入文件過程中遇到錯誤,include會提示錯誤并繼續執行,而require會終止運行。
inclue_once和require_once則保證腳本執行期間的文件引用不超過1次,避免函數重定義,變量重新賦值等問題。
題目描述2:PHP如何自動加載類文件?
解答:參考“自動加載”一節的內容。