程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> PHP autoload 函數 使用基礎教程

PHP autoload 函數 使用基礎教程

編輯:PHP基礎知識
 

(1) autoload機制概述
在使用PHP的OO模式開發系統時,通常大家習慣上將每個類的實現都存放在一個單獨的文件裡,這樣會很容易實現對類進行復用,同時將來維護時也很便利。這也是OO設計的基本思想之一。在PHP5之前,如果需要使用一個類,只需要直接使用include/require將其包含進來即可。下面是一個實際的例子:

/* Person.class.php */
<?php
class Person {
var $name, $age;
function __construct ($name, $age)
{
$this->name = $name;
$this->age = $age;
}
}
?>

/* no_autoload.php */
<?php
require_once (”Person.class.php”);
$person = new Person(”Altair”, 6);
var_dump ($person);
?>

在這個例子中,no-autoload.php文件需要使用Person類,它使用了require_once將其包含,然後就可以直接使用Person類來實例化一個對象。

但隨著項目規模的不斷擴大,使用這種方式會帶來一些隱含的問題:如果一個PHP文件需要使用很多其它類,那麼就需要很多的require/include語句,這樣有可能會造成遺漏或者包含進不必要的類文件。如果大量的文件都需要使用其它的類,那麼要保證每個文件都包含正確的類文件肯定是一個噩夢。

PHP5為這個問題提供了一個解決方案,這就是類的自動裝載(autoload)機制。autoload機制可以使得PHP程序有可能在使用類時才自動包含類文件,而不是一開始就將所有的類文件include進來,這種機制也稱為lazy loading。

下面是使用autoload機制加載Person類的例子:

/* autoload.php */
<?php
function __autoload($classname) {
require_once ($classname . “class.php”);
}
$person = new Person(”Altair”, 6);
var_dump ($person);
?>
通常PHP5在使用一個類時,如果發現這個類沒有加載,就會自動運行__autoload()函數,在這個函數中我們可以加載需要使用的類。在我們這個簡單的例子中,我們直接將類名加上擴展名”.class.php”構成了類文件名,然後使用require_once將其加載。從這個例子中,我們可以看出autoload至少要做三件事情,第一件事是根據類名確定類文件名,第二件事是確定類文件所在的磁盤路徑(在我們的例子是最簡單的情況,類與調用它們的PHP程序文件在同一個文件夾下),第三件事是將類從磁盤文件中加載到系統中。第三步最簡單,只需要使用include/require即可。要實現第一步,第二步的功能,必須在開發時約定類名與磁盤文件的映射方法,只有這樣我們才能根據類名找到它對應的磁盤文件。

因此,當有大量的類文件要包含的時候,我們只要確定相應的規則,然後在__autoload()函數中,將類名與實際的磁盤文件對應起來,就可以實現lazy loading的效果。從這裡我們也可以看出__autoload()函數的實現中最重要的是類名與實際的磁盤文件映射規則的實現。
但現在問題來了,如果在一個系統的實現中,如果需要使用很多其它的類庫,這些類庫可能是由不同的開發人員編寫的,其類名與實際的磁盤文件的映射規則不盡相同。這時如果要實現類庫文件的自動加載,就必須在__autoload()函數中將所有的映射規則全部實現,這樣的話__autoload()函數有可能會非常復雜,甚至無法實現。最後可能會導致__autoload()函數十分臃腫,這時即便能夠實現,也會給將來的維護和系統效率帶來很大的負面影響。在這種情況下,難道就沒有更簡單清晰的解決辦法了吧?答案當然是:NO! 在看進一步的解決方法之前,我們先來看一下PHP中的autoload機制是如何實現的。

(2) PHP的autoload機制的實現

我們知道,PHP文件的執行分為兩個獨立的過程,第一步是將PHP文件編譯成普通稱之為OPCODE的字節碼序列(實際上是編譯成一個叫做zend_op_array的字節數組),第二步是由一個虛擬機來執行這些OPCODE。PHP的所有行為都是由這些OPCODE來實現的。因此,為了研究PHP中autoload的實現機制,我們將autoload.php文件編譯成opcode,然後根據這些OPCODE來研究PHP在這過程中都做了些什麼:

/* autoload.php 編譯後的OPCODE列表,是使用作者開發的OPDUMP工具
*/
1: <?php
2: // require_once (”Person.php”);
3:
4: function __autoload ($classname) {
0 NOP
0 RECV 1
5: if (!class_exists($classname)) {
1 SEND_VAR !0
2 DO_FCALL ‘class_exists’ [extval:1]
3 BOOL_NOT $0 =>RES[~1]
4 JMPZ ~1, ->8
6: require_once ($classname. “.class.php”);
5 CONCAT !0, ‘.class.php’ =>RES[~2]
6 INCLUDE_OR_EVAL ~2, REQUIRE_ONCE
7: }
7 JMP ->8
8: }
8 RETURN null
9:
10: $p = new Person(’Fred’, 35);
1 FETCH_CLASS ‘Person’ =>RES[:0]
2 NEW :0 =>RES[$1]
3 SEND_VAL ‘Fred’
4 SEND_VAL 35
5 DO_FCALL_BY_NAME [extval:2]
6 ASSIGN !0, $1
11:
12: var_dump ($p);
7 SEND_VAR !0
8 DO_FCALL ‘var_dump’ [extval:1]
13: ?>

在autoload.php的第10行代碼中我們需要為類Person實例化一個對象。因此autoload機制一定會在該行編譯後的opcode中有所體現。從上面的第10行代碼生成的OPCODE中我們知道,在實例化對象Person時,首先要執行FETCH_CLASS指令。我們就從PHP對FETCH_CLASS指令的處理過程開始我們的探索之旅。  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved