深入理解PHP之require include順序

2022-07-04 05:09:12 字數 2738 閱讀 5287

)在大型的web專案中, include_path是乙個模組化設計的根本中的根本(當然,現在也有很多基於autoload的設計, 這個不影響本文的**), 但是正是因為include_path, 經常會讓我們遇到一些因為沒有找到正確的檔案而導致的看似」詭異」的問題.

也就有了如下的疑問:

include_path是怎麼起作用的?

如果有多個include_path順序是怎麼樣的?

什麼情況下include_path不起作用?

今天, 我就全面的介紹下這個問題, 先從乙個例子開始吧.

如下的目錄結構:

root

├ 1.php

├ 3.php

└ subdir

├ 2.php

└ 3.php

在1.php中:

<?php

ini_set("include_path", ".:path_to_subdir");

require("2.php");

?>

而在2.php中:

<?php

require("3.php");

?>

而在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」.

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」而異常退出.

後記

2. 因為目錄相對路徑的basedir, 永遠都是當前工作路徑, 如果要使用, 需要和實際部署路徑相關, 所以實際使用的很少(當然, 也有借助chdir來完成的模組).

3. 在模組化的系統設計中, 一般應該在模組內, 通過獲取模組的部署路徑(dirname(__file__), php5.3以後更是提供了__dir__常量)從而使用絕對路徑.

深入理解PHP之陣列遍歷

經常會有人問我,php的陣列,如果用foreach來訪問,遍歷的順序是固定的麼?以什麼順序遍歷呢?比如 又比如 arr 2 huixinchen arr 1 2007 arr 0 2008 foreach arr as key val 要完全了解清楚這個問題,我想首先應該要大家了解php陣列的內部實...

深入理解php核心

第二章 使用者 的執行 第三節 zend引擎與指令碼執行 第四節 小結 第三章 變數及資料型別 第二節 常量 第三節 預定義變數 第四節 靜態變數 第五節 型別提示的實現 第六節 變數的生命週期 第七節 資料型別轉換 第八節 小結 第四章 函式的實現 第二節 函式的定義,引數及返回值 第三節 函式的...

深入理解php核心

第二章 使用者 的執行 第三節 zend引擎與指令碼執行 第四節 小結 第三章 變數及資料型別 第二節 常量 第三節 預定義變數 第四節 靜態變數 第五節 型別提示的實現 第六節 變數的生命週期 第七節 資料型別轉換 第八節 小結 第四章 函式的實現 第二節 函式的定義,引數及返回值 第三節 函式的...