在大型的Web項目中, include_path是一個模塊化設計的根本中的根本(固然,如今也有不少基於autoload的設計, 這個不影響本文的探討), 可是正是由於include_path, 常常會讓咱們遇到一些由於沒有找到正確的文件而致使的看似」詭異」的問題.php
也就有了以下的疑問:html
include_path是怎麼起做用的?模塊化
若是有多個include_path順序是怎麼樣的?性能
什麼狀況下include_path不起做用?ui
今天, 我就全面的介紹下這個問題, 先從一個例子開始吧.google
以下的目錄結構:url
在1.php中:spa
root ├ 1.php ├ 3.php └ subdir ├ 2.php └ 3.php
而在2.php中:設計
<?php require("3.php"); ?>而在root目錄下的3.php打印出」root」, 在subdir目錄下的3.php打印出」subdir」;
如今, 個人問題來了:htm
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」.
3. 由於沒有了當前路徑爲include_path, 因此在root目錄下運行的時候2.php中包含3.php的時候, 是path_to_subdir起了做用, 因此不管在root仍是subdir都將獲得」subdir」的輸出.
而若是在2.php中清空include_path,
<?php ini_set("include_path", ''); require("3.php"); ?>
那麼將會是current_script_dir起做用, 而這個時候current_script_dir是2.php的路徑, 因此仍是會獲得」subdir」的輸出.
目錄相對路徑
在使用目錄相對路徑的狀況下, 相對路徑的基點, 永遠都是當前工做目錄.
爲了說明在目錄相對路徑下的狀況,咱們再看個列子, 仍是上面的目錄結構, 只不過1.php變成了:
<?php ini_set("include_path", "/"); require("./subdir/2.php"); ?>
2.php變成了:
<?php require("./3.php"); ?>
若是在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__常量)從而使用絕對路徑.