熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> PHP編程 >> 正文

請離開include

2013-11-15 12:24:05  來源: PHP編程 
盡量使用include 而不是include_once 理由是 include_once需要查詢一遍已加載的文件列表 確認是否存在 然後再加載  

  誠然 這個理由是對的 不過 我今天要說的 是另外一個的原因
我們知道 PHP去判斷一個文件是否被加載 是需要得到這個文件的opened_path的 意思是說 比如:

復制代碼 代碼如下:
    <?php
    set_include_path("/tmp/:/tmp/");
    include_once("php");
    ?>

  
當 PHP看到include_once “php”的時候 他並不知道這個文件的實際路徑是什麼 也就無法從已加載的文件列表去判斷是否已經加載 所以在include_once的實現中 會首先嘗試解析這個文件的真實路徑(對於普通文件這個解析僅僅類似是檢查getcwd和文件路徑 所以如果是相對路徑 一般是不會成功) 如果解析成功 則查找EG(include_files) 如果存在則說明包含過了 返回 否則open這個文件 從而得到這個文件的opened_path 比如上面的例子 這個文件存在於 “/tmp/php”

然後 得到了這個opened_path以後 PHP去已加載的文件列表去查找 是否已經包含 如果沒有包含 那麼就直接compile 不再需要open file了

   嘗試解析文件的絕對路徑 如果能解析成功 則檢查EG(included_files) 存在則返回 不存在繼續
打開文件 得到文件的打開路徑(opened path)
拿opened path去EG(included_files)查找 是否存在 如果存在則返回 不存在繼續
編譯文件(compile_file)

  這個在大多數情況下 不是問題 然而問題出在當你使用APC的時候…

在使用APC的時候 APC劫持了compile_file這個編譯文件的指針 從而直接從cache中得到編譯結果 避免了對實際文件的open 避免了對open的system call

然 而 當你在代碼中使用include_once的時候 在compile_file之前 PHP已經嘗試去open file了 然後才進入被APC劫持的compile file中 這樣一來 就會產生一次額外的open操作 而APC正是為了解決這個問題 引入了include_once_override 在include_once_override開啟的情況下 APC會劫持PHP的ZEND_INCLUDE_OR_EVAL opcode handler 通過stat來確定文件的絕對路徑 然後如果發現沒有被加載 就改寫opcode為include 做一個tricky解決方案

但是 很可惜 如我所說 APC的include_once_override實現的一直不好 會有一些未定義的問題 比如:

復制代碼 代碼如下:
    <?php
    set_include_path("/tmp");
    function a($arg = array()) {
        include_once("bphp");
    }

    a();
    a();
    ?>

  
然後 我們的bphp放置在”/tmp/bphp” 內容如下:

復制代碼 代碼如下:
    <?php
      class B {}
    ?>

  
那麼在打開apcinclude_once_override的情況下 連續訪問就會得到如下錯誤:
Fatal error include() : Cannot redeclare class

  排除這些技術因素 我也一直認為 我們應該使用include 而不是include_once 因為我們完全能做到自己規劃 一個文件只被加載一次 還可以借助自動加載 來做到這一點

  你使用include_once只能證明 你對自己的代碼沒信心
所以 建議大家 不要再使用include_once


From:http://tw.wingwit.com/Article/program/PHP/201311/20878.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.