PHP學習系列 -- include(require)注意事項
一、背景
好的框架、設計會遵循高內聚低耦合的設計原則,解耦模組、元件、類之間的依賴關係,做到程式碼的可複用。
PHP裡的程式碼複用有多種形式,今天我們先以常見的include/require檔案包含為例一起學習一下檔案包含複用的相關知識,希望對大家有所幫助。
二、學習
1. 基礎知識學習
- include/require都是用於檔案的包含操作,與之對應的還有include_once/require_once。
- 簡單來說,*_once只會進行一次包含操作,require更嚴謹,在檔案不存在時會丟擲一個致命錯誤。
- 被包含檔案先按引數給出的路徑尋找,如果沒有給出目錄(只有檔名)時則按照
- 如果定義了路徑——不管是絕對路徑(在 Windows 下以碟符或者 \ 開頭,在 Unix/Linux 下以 / 開頭)還是當前目錄的相對路徑(以 . 或者 .. 開頭)——include_path 都會被完全忽略。例如一個檔案以 ../ 開頭,則解析器會在當前目錄的父目錄下尋找該檔案。
- 當一個檔案被包含時,其中所包含的程式碼繼承了 include 所在行的變數範圍。從該處開始,呼叫檔案在該行處可用的任何變數在被呼叫的檔案中也都可用。不過所有在包含檔案中定義的函式和類都具有全域性作用域。
2. 實踐
檔案包含中最重要的兩項就是檔案巢狀包含和變數範圍,而且require與include使用起來無太大差異,下面的實踐就以include為例演示。
一共有兩個目錄和一個index.php檔案,目錄結構如下。
其中,index.php檔案中include了Dir1/A.php檔案,A.php中又include了Dir2/B.php檔案。這裡我們使用三種方式inlclude檔案,記住我們上面說的一句話:include相當於把被包含檔案放到了當前檔案的引用位置處。
1.巢狀包含
情景1:使用相對路徑
各檔案內容如下:
index.php
<?php
include('./Dir1/A.php');
echo 'this is index.php file!'.PHP_EOL;
?>
Dir1/A.php
<?php
include('./Dir2/B.php');
echo 'this is A.php file!'.PHP_EOL;
?>
Dir2/B.php
<?php
echo 'this is B.php'.PHP_EOL;
?>
注意:上面引入Dir1/A.php和Dir2/B.php檔案時,引入路徑都是相對於index.php的。
輸出截圖如下:
情景2:使用絕對路徑
各檔案內容如下:
index.php
<?php
define('APP_PATH', dirname(__FILE__));
include(APP_PATH .'/Dir1/A.php');
echo 'this is index.php file!'.PHP_EOL;
?>
Dir1/A.php
<?php
include(APP_PATH . '/Dir2/B.php');
echo 'this is A.php file!'.PHP_EOL;
?>
Dir2/B.php 該檔案與情景1一樣
這種方式通過APP_PATH定義了一個路徑常量,所有的檔案引入都是使用的絕對路徑。
輸出結果和情景1是一樣的
情景3:使用路徑函式生成絕對路徑
index.php
<?php
include(dirname(__FILE__) .'/Dir1/A.php');
echo 'this is index.php file!'.PHP_EOL;
?>
Dir1/A.php
<?php
include(dirname(__FILE__) . '/../Dir2/B.php');
echo 'this is A.php file!'.PHP_EOL;
?>
Dir2/B.php 該檔案和上面的一樣。
注意:這裡我們是使用的dirname(__FILE__)方式引入的檔案,你可能會有疑問,include不是相當於把檔案直接insert到引入處嗎?這樣的話dirname(__FILE__)不是表示index.php檔案的絕對路徑嗎?其實,你可以這樣理解,指令碼執行時,碰到include的檔案,會同時執行一遍被引入檔案的內容,這個也可以通過下面的變數範圍學習驗證一下。
輸出結果和情景1是一樣的。
2.變數範圍
重新修改一下index.php和Dir1/A.php兩個檔案:在index.php中定義一個變數$indexVariable並輸出Dir1/A.php中定義的一個變數$bVariable;在Dir1/A.php中定義一個變數$bVariable並輸出index.php中定義的一個變數$indexVariable。具體程式碼如下:
index.php
<?php
$indexVariable = 'this is index variable!';
include(dirname(__FILE__) .'/Dir1/A.php');
echo $bVariable;
echo 'this is index.php file!'.PHP_EOL;
?>
Dir1/A.php
<?php
echo $indexVariable.PHP_EOL;
$bVariable = 'this is A.php vairable'.PHP_EOL;
include(dirname(__FILE__) . '/../Dir2/B.php');
echo 'this is A.php file!'.PHP_EOL;
?>
輸出截圖如下:
解釋一下:index.php中$indexVariable變數是在include之前定義的,所以後續的程式碼以及include的程式碼(Dir1/A.php)內都可以訪問;$bVariable變數是在Dir1/A.php中定義的,當前檔案以及引入A.php檔案之後的所有程式碼都可以訪問,所以在index.php中可以正常輸出。
我現在修改一下index.php程式碼:在include(Dir1/A.php)之前echo $bVariable變數。
<?php
echo 'bVariable:' . $bVariable . PHP_EOL;
$indexVariable = 'this is index variable!';
include(dirname(__FILE__) .'/Dir1/A.php');
echo 'this is index.php file!'.PHP_EOL;
?>
大家猜一下結果會是什麼,哈哈,答案當然是取不到$bVariable變數值了。
三、總結
- 注意變數的範圍,被引入的檔案中定義的變數在之後的程式碼中都可以被訪問;在include之上定義的全域性變數在被include的檔案中也可以訪問。
- 不要在檔案包含中使用相對路徑,這樣一方面將共享檔案與想要引用該檔案的檔案緊耦合,舉個例子,在Dir3目錄下的index2.php也想引用A.php檔案,情景1的處理還可行嗎?;處理之外,使用相對路徑還會降低程式的效能:需要遍歷目錄結果確定引用的檔案是否存在,會增加I/O開銷。