本文章來(lái)給各位朋友介紹php中include_once和require_once性能分析,有需要了解的朋友不防參考參考.
我們知道, PHP去判斷一個(gè)文件是否被加載, 是需要得到這個(gè)文件的opened_path的.
實(shí)例代碼如下:
當(dāng)PHP看到include_once “2.php”的時(shí)候, 他并不知道這個(gè)文件的實(shí)際路徑是什么, 也就無(wú)法從已加載的文件列表去判斷是否已經(jīng)加載, 所以在include_once的實(shí)現(xiàn)中, 會(huì)首先嘗試解析這個(gè)文件的真實(shí)路徑(對(duì)于普通文件這個(gè)解析僅僅類似是檢查getcwd和文件路徑, 所以如果是相對(duì)路徑, 一般是不會(huì)成功), 如果解析成功, 則查找EG(include_files), 如果存在則說(shuō)明包含過(guò)了, 返回, 否則open這個(gè)文件, 從而得到這個(gè)文件的opened_path. 比如上面的例子, 這個(gè)文件存在于 “/tmp2/2.php”.
然后, 得到了這個(gè)opened_path以后, PHP去已加載的文件列表去查找, 是否已經(jīng)包含, 如果沒(méi)有包含, 那么就直接compile, 不再需要open file了.
1. 嘗試解析文件的絕對(duì)路徑, 如果能解析成功, 則檢查EG(included_files), 存在則返回, 不存在繼續(xù)
2. 打開(kāi)文件, 得到文件的打開(kāi)路徑(opened path)
3. 拿opened path去EG(included_files)查找, 是否存在, 如果存在則返回, 不存在繼續(xù)
4. 編譯文件(compile_file)這個(gè)在大多數(shù)情況下, 不是問(wèn)題, 然而問(wèn)題出在當(dāng)你使用APC的時(shí)候…
在使用APC的時(shí)候, APC劫持了compile_file這個(gè)編譯文件的指針, 從而直接從cache中得到編譯結(jié)果, 避免了對(duì)實(shí)際文件的open, 避免了對(duì)open的system call.然而, 當(dāng)你在代碼中使用include_once的時(shí)候, 在compile_file之前, PHP已經(jīng)嘗試去open file了, 然后才進(jìn)入被APC劫持的compile file中, 這樣一來(lái), 就會(huì)產(chǎn)生一次額外的open操作. 而APC正是為了解決這個(gè)問(wèn)題, 引入了include_once_override, 在include_once_override開(kāi)啟的情況下, APC會(huì)劫持PHP的ZEND_INCLUDE_OR_EVAL opcode handler, 通過(guò)stat來(lái)確定文件的絕對(duì)路徑, 然后如果發(fā)現(xiàn)沒(méi)有被加載, 就改寫opcode為include, 做一個(gè)tricky解決方案.但是, 很可惜, 如我所說(shuō), APC的include_once_override實(shí)現(xiàn)的一直不好, 會(huì)有一些未定義的問(wèn)題.
實(shí)例代碼如下:
然后, 我們的b.php放置在”/tmp/b.php”, 內(nèi)容如下:
實(shí)例代碼如下
那么在打開(kāi)apc.include_once_override的情況下, 連續(xù)訪問(wèn)就會(huì)得到如下錯(cuò)誤:
Fatal error – include() : Cannot redeclare class
排除這些技術(shù)因素, 我也一直認(rèn)為, 我們應(yīng)該使用include, 而不是include_once, 因?yàn)槲覀兺耆茏龅阶约阂?guī)劃, 一個(gè)文件只被加載一次. 還可以借助自動(dòng)加載, 來(lái)做到這一點(diǎn).你使用include_once,只能證明, 你對(duì)自己的代碼沒(méi)信心.所以, 建議大家, 不要再使用include_once,不過(guò)我建義大家使用autoload和spl_autoload自動(dòng)加載
(1) autoload機(jī)制概述
在使用PHP的OO模式開(kāi)發(fā)系統(tǒng)時(shí),通常大家習(xí)慣上將每個(gè)類的實(shí)現(xiàn)都存放在一個(gè)單獨(dú)的文件里,這樣會(huì)很容易實(shí)現(xiàn)對(duì)類進(jìn)行復(fù)用,同時(shí)將來(lái)維護(hù)時(shí)也很便利.這 也是OO設(shè)計(jì)的基本思想之一.在PHP5之前,如果需要使用一個(gè)類,只需要直接使用include/require將其包含進(jìn)來(lái)即可.下面是一個(gè)實(shí)際的例子:
實(shí)例代碼如下
在這個(gè)例子中,no-autoload.php文件需要使用Person類,它使用了require_once將其包含,然后就可以直接使用Person類來(lái)實(shí)例化一個(gè)對(duì)象.但隨著項(xiàng)目規(guī)模的不斷擴(kuò)大,使用這種方式會(huì)帶來(lái)一些隱含的問(wèn)題:如果一個(gè)PHP文件需要使用很多其它類,那么就需要很多的require/include語(yǔ) 句,這樣有可能會(huì)造成遺漏或者包含進(jìn)不必要的類文件.如果大量的文件都需要使用其它的類,那么要保證每個(gè)文件都包含正確的類文件肯定是一個(gè)噩夢(mèng).
PHP5為這個(gè)問(wèn)題提供了一個(gè)解決方案,這就是類的自動(dòng)裝載(autoload)機(jī)制.autoload機(jī)制可以使得PHP程序有可能在使用類時(shí)才自動(dòng)包含類文件,而不是一開(kāi)始就將所有的類文件include進(jìn)來(lái),這種機(jī)制也稱為lazy loading.下面是使用autoload機(jī)制加載Person類的例子:
實(shí)例代碼如下: