php關鍵詞 php中用於檔案包含的關鍵詞有:include、include_once、require、require_once。一般來說,把include和require分在一組裡,而include_once和require_once是一種改進完善形式。本文通過研究include和require的性質,兼顧include_once和require_once,獲得php檔案包含的基本知識和潛在問題,並提供一個可行的解決方案。被包含檔案的類型
使用包含關鍵詞包含的檔案,只要是文字檔,php解析器都將檔案的內容作為php檔案處理。
也即php解析器將當前執行指令碼的包含檔案讀出後,將php嵌入標籤中的內容作為原始碼執行,而其他沒有被標籤包含的將作為文本直接輸出。 設有兩個檔案a和b.php,內容分別如下:
| a |
| akjfladskjfla<br><?echo $_SERVER['PHP_SELF'],'<br>';echo 'I am A<br>';?> |
| b.php |
| <?phpinclude 'a';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am B<br>';?> |
輸出如下:
|
akjfladskjfla /webapp/codesnipe/b.php I am A /webapp/codesnipe/b.php I am B |
檔案a無尾碼名,其中包含了一個php嵌入標籤。如果執行檔案a,系統將會報錯。但是在檔案b中,包含了檔案a。沒有被包含在php嵌入標籤中的文本被直接輸出,而包含在標籤中的文本作為php原始碼執行。資訊格式 還是上面的實驗,我們把檔案a刪除,運行b.php。報錯資訊如下:
|
| Warning: include(a) [function.include]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3 Warning: include() [function.include]: Failed opening 'a' for inclusion (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3 /webapp/codesnipe/b.php I am B
|
可以對照上面,總結出報錯資訊的格式如下:
語句或函數:failed to open stream:具體的提示資訊,在檔案的第幾行
include和require的區別
當遇到檔案找不到的情況是,它們的處理不同。include會發出警告,然後繼續執行下去;require則報錯,並停止當前指令碼的執行。
資訊格式中給出的警告格式就是include發出的。兩個警告之後就是b.php的輸出內容。如果將include換成require,則資訊如下:
|
| Warning: require(a) [function.require]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3 Fatal error: require() [function.require]: Failed opening required 'a' (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/b.php on line 3
|
可見,它們資訊的格式相同,而且require第二個資訊變成了Fatal error。錯誤資訊後也沒有b.php執行後的輸出,因為require報錯之後就是的指令碼的執行退出了。檔案包含的死迴圈 最簡單的死迴圈形式是兩個檔案的形式:a.php和b.php。如果a.php中包含檔案b.php,而b.php中包含檔案a.php,則無論執行a.php還是b.php,都會進入死迴圈。
只要將第一個例子中的a加上包含b.php的語句,就可以得到一個很好的例子。死迴圈的原因還容易理解,這裡不做解釋。可能有人覺得項目開發時不會犯這種低級的錯誤。項目小的時候可能正確,但是一個大型的軟體多人合作,如何保證沒有潛在的執行環呢?再說,從維護的角度來說,這種設計也不合理。include_once和require_once include_once和require_once在第一次執行時,其結果和include和require一樣。其後再遇到檔案包含關鍵詞(同組的關鍵詞)則會跳過不執行。
假設有三個檔案:indexa.php、indexb.php和indexc.php。其原始碼如下:
| indexa.php |
| <?phpinclude_once 'indexb.php';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am A<br>';?> |
| indexb.php |
| <?phpinclude_once 'indexa.php';include_once 'indexc.php';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am B<br>';?> |
| indexc.php |
| <?phpinclude_once 'indexb.php';include_once 'indexa.php';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am C<br>';?> |
輸出如下:
|
/webapp/codesnipe/indexa.php I am C /webapp/codesnipe/indexa.php I am B /webapp/codesnipe/indexa.php I am A |
執行檔案indexa.php,遇到包含語句包含indexb.php,所以讀入indexb.php的原始碼。indexb.php的原始碼的第一句就包含檔案indexa.php。由於indexa.php的內容已經存在,故該包含語句無效;第二局包含indexc.php。indexc.php的原始碼的第一句包含檔案indexb.php。基於indexb.php的內容已經存在,故該語句同樣無效;同樣的第二個語句也無效。最後程式執行,結果就如上面所示。 將任一個include_once語句換成require_once,程式執行一樣。因而在同組內,處理錯誤處理不同,並沒有什麼差別。 為了更形象地理解,我們可以設想php解析器會給每個執行檔案建立一個原始碼來源記錄表。記錄表記錄了原始碼被包含進來的檔案完整路徑。include_once和require_once會在每次包含新檔案時,檢查新檔案是否已經在記錄表中。如果已經存在,檔案內容不會被包含進來;否則檔案路徑被記錄入記錄表,並將其內容包含進來。與前一組的區別 這裡不需要多說,include和require並不檢查記錄表,這就是差別。通過這種方式,我們很容易解決潛在的死迴圈的問題,提高程式的可靠性。目錄結構導致的錯誤 檔案包含除了受到檔案內含項目關聯性影響,第二個重要因素就是檔案包含的目錄結構。前面的原始碼中我都包含了變數$_SERVER['PHP_SELF']的值。從輸出中可以看出變數的值是當前正在啟動並執行指令碼的名稱,就是直接運行請求的php檔案而不是包含進來的檔案。這個事實說明,被包含檔案的原始碼將被執行在直接執行檔案的環境中,不如最終要的檔案尋找路徑。 一個簡單的例子。項目包含一個檔案夾include,下面是兩個檔案indexb.php和indexc.php。和檔案夾include同目錄的是檔案indexa.php。原始碼如下:
| indexa.php |
| <?phpinclude_once 'include/indexb.php';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am A<br>';?> |
| indexb.php |
| <?phpinclude_once './indexc.php';
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am B<br>';?> |
| indexc.php |
| <?php
echo $_SERVER['PHP_SELF'],'<br>';echo 'I am C<br>';?> |
輸出如下:
|
| Warning: include_once(./indexc.php) [function.include-once]: failed to open stream: No such file or directory in C:/xampp/htdocs/webapp/codesnipe/include/indexb.php on line 3 Warning: include_once() [function.include]: Failed opening './indexc.php' for inclusion (include_path='.;C:/xampp/php/pear/') in C:/xampp/htdocs/webapp/codesnipe/include/indexb.php on line 3 /webapp/codesnipe/indexa.php I am B /webapp/codesnipe/indexa.php I am A
|
上面的輸出可以看出,indexb.php的原始碼中的"./indexc.php"中的"."指向的是indexa.php所在的目錄而不是include目錄本身,因而導致檔案尋找錯誤。如果把indexb.php中的"./indexc.php"改成"indexc.php",那麼指令碼將正常運行。這是因為php本身會有一個預設的檔案尋找路徑值。但是從可維護性角度來說,這種僥倖的正確時不可行的。一個解決方案 由於存在上面的問題,所以項目設計時會有一個系統的設定檔,在設定檔中設定系統的路徑值,通過這種方式來獲得要包含檔案的絕對路徑,從而避免上面的問題。具體的說明可見下一篇文章。