1. 程式人生 > >PHP學習系列 -- include(require)注意事項

PHP學習系列 -- include(require)注意事項

一、背景

好的框架、設計會遵循高內聚低耦合的設計原則,解耦模組、元件、類之間的依賴關係,做到程式碼的可複用。

PHP裡的程式碼複用有多種形式,今天我們先以常見的include/require檔案包含為例一起學習一下檔案包含複用的相關知識,希望對大家有所幫助。

二、學習

1. 基礎知識學習

  1. include/require都是用於檔案的包含操作,與之對應的還有include_once/require_once。
  2. 簡單來說,*_once只會進行一次包含操作,require更嚴謹,在檔案不存在時會丟擲一個致命錯誤。
  3. 被包含檔案先按引數給出的路徑尋找,如果沒有給出目錄(只有檔名)時則按照
    include_path
    指定的目錄尋找。如果在 include_path 下沒找到該檔案則 include 最後才在呼叫指令碼檔案所在的目錄和當前工作目錄下尋找。如果最後仍未找到檔案則 include 結構會發出一條警告;這一點和 require 不同,後者會發出一個致命錯誤。
  4. 如果定義了路徑——不管是絕對路徑(在 Windows 下以碟符或者 \ 開頭,在 Unix/Linux 下以 / 開頭)還是當前目錄的相對路徑(以 . 或者 .. 開頭)——include_path 都會被完全忽略。例如一個檔案以 ../ 開頭,則解析器會在當前目錄的父目錄下尋找該檔案。
  5. 當一個檔案被包含時,其中所包含的程式碼繼承了 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變數值了。

三、總結

  1. 注意變數的範圍,被引入的檔案中定義的變數在之後的程式碼中都可以被訪問;在include之上定義的全域性變數在被include的檔案中也可以訪問。
  2. 不要在檔案包含中使用相對路徑,這樣一方面將共享檔案與想要引用該檔案的檔案緊耦合,舉個例子,在Dir3目錄下的index2.php也想引用A.php檔案,情景1的處理還可行嗎?;處理之外,使用相對路徑還會降低程式的效能:需要遍歷目錄結果確定引用的檔案是否存在,會增加I/O開銷。