[PHP] PHP 密技: include 與 require
可以接受回傳資料?
先調查一下,知道 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 的密技嗎?歡迎大家一起討論囉~
看來還有很多東西我有待學習~
謝謝你的教學~
瞠目結舌中…
這個在特殊場合再用會比較合適, 因為容易造成困擾.
以前(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 或許適合一些.. (當然, 還是和使用場合和時機有關),
To Rack:
感謝說明~
include 能回傳值這個特性其實以前在寫 PHP4 時就用過了,只是能把這個特性用在參數上這我倒是第一次曉得。
不過我也認為目前 include 使用 return 對我而言已經不太適用;除非我的 Framework 要像 Zend_DI 那篇文章這樣使用 Zend_Config ,不過目前還不打算支援這種特性。
include(), require() 在 php 裡就跟一般的 function 特性是完全一樣的, 所以不用覺得很訝異
如果懂一點 php extension 的概念, 我想就更容易理解了..
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 語言還不是那麼熟,還有望這方面的高手來解惑。
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()
因為 include 與 eval 在原 source code 是同樣一段程式, 最後也沒有再區分回傳值, 所以 include() 的回傳值型態跟 eval() 一樣是 mixed
To jj:
感謝這麼詳細的說明呀~
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