而在root目錄下的3.php印出」root”, 在subdir目錄下的3.php印出」subdir”; 現在, 問題來了: 1. 當在root目錄下運行1.php, 會得到什麼輸出? 2. 在subdir下運行上一級目錄的1.php, 有會得到什麼輸出? 3. 當取消include_path中的目前目錄path(也就是include_path=”path_to_subdir”), 上面兩個問題又會是什麼輸出? PHP中的include_path PHP在遇到require(_once)/include(_once)的指令的時候, 首先會做如下的判斷: 要包含的檔案路徑是絕對路徑麼? 如果是, 則直接包含, 並結束. 如果不是, 進入另外的邏輯(經過多次呼叫, 巨集展開後進入_php_stream_fopen_with_path)尋找此檔案. 接下來, 在_php_stream_fopen_with_path, 會做以下判斷: 要包含的檔案路徑是相對路徑麼(形如./file, ../dir/file, 以下用"目錄相對路徑取代")? 如果是, 則跳過include_path的作用邏輯, 直接解析相對路徑(隨後單獨介紹). 會根據include_path,和目前執行檔的path組成一個待選的目錄列表, 例如對於文章前面的例子來說, 會形成一個如下的待選列表 ".:path_to_subdir:current_script_dir" 然後, 依序從待選列表頭部開始, 根據DEFAULT_DIR_SEPARATOR(本文的環境是”:”)取出待選列表中的一個路徑, 然後把要包含的文件名附加在這個路徑後面, 進行嘗試.如果成功包含, 則回傳, 否則繼續下一個待選路徑. 到現在為止, 我們已經可以回答我開頭提出的3個問題了. 1. 因為在root目錄下執行, 所以在1.php中包含2.php的時候, include_path的第二個待選路徑起了作用(path_to_subdir), 找到了path_to_subdir/2.php, 在2.php包含3.php的時候, 目前工作目錄是root下, 所以在包含3.php的時候, include_path的第一個待選路徑”.”(當前工作目錄)下就找到的匹配的文件,所以得到的輸出是”root”. 2. 同1, 只不過當前的路徑是subdir, 所以得到的輸出是”subdir”.
那麼將會是current_script_dir起作用, 而這個時候current_script_dir是2.php的路徑, 所以還是會得到」subdir」的輸出. 目錄相對路徑 在使用目錄相對路徑的情況下, 相對路徑的基點, 永遠都是當前工作目錄.
如果在root目錄下執行, 2.php中尋找3.php將會在當前目錄的相對路徑下尋找, 所以得到的輸出是”root”, 而如果是在subdir下執行上一級目錄的1.php(php -f ../1.php), 將會因為在subdir下找不到”./subdir/2.php”而異常退出. 總結 1. 因為使用include_path和相對路徑的情況下,效能會和尋找的次數有關,最壞的情況下,如果你有10個include_path,那麼最多可能會重試11次才能找到要包含的文件,所以,在能使用絕對路徑的情況下最好使用絕對路徑。 2. 因為目錄相對路徑的basedir,永遠都是當前工作路徑,如果要使用,需要和實際部署路徑相關,所以實際使用的很少(當然,也有藉助chdir來完成的模組)。 3. 在模組化的系統設計中,一般應該在模組內,透過取得模組的部署路徑(dirname(__FILE__),php5.3以後更是提供了__DIR__常數)從而使用絕對路徑。 |