首頁 > PHP > [PHP] PHP 密技: include 與 require

[PHP] PHP 密技: include 與 require

2008年2月22日 jaceju 發表評論 閱讀評論

可以接受回傳資料?

先調查一下,知道 include 或 require 可以取得回傳資料的請舉手… (眺望)

呃…不知道的朋友也不用煩惱,我來解釋一下。

如何回傳資料呢?假設現在有個 php 檔叫做 config.php ,內容如下:

<?php
return array('123', '456');

咦?那邊有人說 return 放錯地方了?不不不, PHP 能接受這樣的寫法。

好,現在我們來證明 include 或 require 能取得 config.php 所 return 回來的資料。請建立一支 test.php ,其內容是:

$config = require 'config.php';
var_dump($config);

執行看看,是不是可以跑呀?

所以我們可以在某支 PHP 程式中 return 一個資料 (任何型態) ,然後在另一支 PHP 程式中用 include 或 require 來取得這個資料。

把 require 放在參數裡

什麼?這不是密技?不不不,密技在底下:

function test($config) {
    var_dump($config);
}
test(require 'config.php');

對!你沒看錯!直接把 require 放在函式的參數裡!

還沒完呢,再看:

class Test
{
    public function __construct($config)
    {
        var_dump($config);
    }
}
$a = new Test(require 'config.php');

連 new 建構子的參數都可以接受 require !

所以只要能放變數的地方,都可以放 include 或 require ,例如:

if (require 'config.php') {
    var_dump(require 'config.php');
}
 
if ($config = require 'config.php') {
    var_dump($config);
}

而且不僅是 include 及 require ,連 include_once 和 require_once 都可以這麼做。

我在某篇文章發現這個密技以後,分享給辦公室裡的同事們;沒想到玩了 PHP 這麼多年的他們也沒看過這個方法,看來大家對 PHP 的瞭解需要更深入一點囉!

Scope 的問題

接著我同事問了我一個問題:如果在參數使用 require 敘述,而且被 require 的 PHP 程式裡如果有定義全域變數的話,那麼這個變數在執行的 PHP 程式裡,它的 scope 在哪裡呢?

答案是:它還是全域。

怎麼說呢?現在我們在剛剛的 config.php 的 return 敘述前加上一行程式,如下:

<?php
$data = '789'; // 加上這行
return array('123', '456');

然後在 test.php 裡的 Global 部份 (也就是不在函式或類別定義裡) 的任意處加入:

var_dump($data);

是不是也可以正確顯示 config.php 中 $data 變數所指定的內容呢?這就表示在參數中使用 require 不會影響全域變數的 scope 。

還有其他 include 或 require 的密技嗎?歡迎大家一起討論囉~

Categories: PHP Tags:
  1. Dylan
    2008年2月22日23:54 | #1

    看來還有很多東西我有待學習~
    謝謝你的教學~

  2. 2008年2月23日10:34 | #2

    瞠目結舌中…

  3. 2008年2月25日09:49 | #3

    這個在特殊場合再用會比較合適, 因為容易造成困擾.
    以前(2002-)(ajax framework 不多時), 因為 include/require 可以直接引入遠端檔案(PHP3就可以的超方便功能), 所以要二支 remote php 交換處理 status 時用到, 如:

    if ((include ‘http://xxx/getStatus.php?id=abc’) == ‘OK’) {
    echo ‘OK’;
    }

    在 php manual 中的 Handling Returns (http://tw2.php.net/manual/tw/function.include.php)中有提到.
    由於我們寫程式, 都是參考 Framework 或專家怎麼寫, 所以在使用上, 比較希望它像其它語言中的 use / include / import 來用比較好.
    需要 include and return , 用 readXXXconfig 或許適合一些.. (當然, 還是和使用場合和時機有關),

  4. jaceju
    2008年2月25日09:57 | #4

    To Rack:

    感謝說明~

    include 能回傳值這個特性其實以前在寫 PHP4 時就用過了,只是能把這個特性用在參數上這我倒是第一次曉得。

    不過我也認為目前 include 使用 return 對我而言已經不太適用;除非我的 Framework 要像 Zend_DI 那篇文章這樣使用 Zend_Config ,不過目前還不打算支援這種特性。

  5. jj
    2008年2月25日22:22 | #5

    include(), require() 在 php 裡就跟一般的 function 特性是完全一樣的, 所以不用覺得很訝異

    如果懂一點 php extension 的概念, 我想就更容易理解了..

  6. jaceju
    2008年2月26日10:12 | #6

    To jj:

    事實上在 PHP 官方手冊中, require 和 include 它們是被歸類成 statement 而非 function 。

    所以有些 function 能用的特性其實 require 和 include 是不能用的,例如 variable functions (http://tw.php.net/manual/en/functions.variable-functions.php) 。這也是為什麼我對它們能放在參數裡感到很訝異的原因,因為它們其實更像 eval 的檔案版。

    不過我查看了一下原始碼, require 和 function 卻是用 function 的形態來實作 (Zend/zend_builtin_functions.c) 。詳細的原因我不確定,我對 C 語言還不是那麼熟,還有望這方面的高手來解惑。

  7. jj
    2008年3月3日21:53 | #7

    to jaceju,
    為了查明原因, 我看了source code, 冏…
    你說的是對的

    真正對應的程式是:
    "Zend/zend_execute.c"
    這一段底下
    case ZEND_INCLUDE_OR_EVAL:

    include, eval 是歸類在一起的, 一個用 compile_filename(), 另一個用compile_string()
    在這段落結束前有處理 return value 的程式

    其他可以再參考 "Zend/zend_compile.c"
    void zend_do_include_or_eval()

  8. jj
    2008年3月3日21:57 | #8

    因為 include 與 eval 在原 source code 是同樣一段程式, 最後也沒有再區分回傳值, 所以 include() 的回傳值型態跟 eval() 一樣是 mixed

  9. jaceju
    2008年3月3日23:32 | #9

    To jj:

    感謝這麼詳細的說明呀~ :)

  10. 2008年12月8日16:35 | #10

    http://www.php.net/manual/en/function.return.php
    http://www.php.net/manual/en/function.include.php

    你講的在這兩個php官方的manual都有提到

    另外我以前有個想法
    就是在遠端Server拋出php碼
    然後用include來接

    以前在玩php-gtk的時候
    就有想要用include這個技巧來
    玩類似java 的webstart
    =====================================================

    記得要在php.ini
    設定這個參數
    allow_url_include = On
    http://www.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen
    =====================================================

    我要貼的被截掉
    貼到我的Blog
    http://lp81sam.spaces.live.com/blog/cns!FE9AB5CD84013FC2!451.entry

Spam Protection by WP-SpamFree