文章目錄
- 一、基礎知識
- 二、預定義變數
- 三、變數範圍
- 四、可變變數
- 五、PHP 的外部變數
很榮幸上篇文章被版主推薦到首頁了,心裡算是激動了一把,繼續努力學習中吧。本章主要介紹PHP中的變數。主要包括:預定義變數、變數範圍、可變變數以及PHP的外部變數等。
一、基礎知識
PHP 中一個貨幣符號後面跟上一個變數名稱,即表示一個變數。變數的名稱是對大小寫敏感的。
變數名與 PHP 中其它的標籤一樣遵循相同的規則。一個有效變數名由字母或者底線開頭,後面跟上任意數量的字母,數字,或者底線。按照正常的Regex,它將被表述為:'[a-zA-Z_/x7f-/xff][a-zA-Z0-9_/x7f-/xff]*'
注: 字母為 a-z,A-Z,ASCII 字元從 127 到 255(0x7f-0xff)。
<?php<br />$var = "Bob";<br />$Var = "Joe";<br />echo "$var, $Var"; // outputs "Bob, Joe"</p><p>$4site = 'not yet'; // invalid; starts with a number<br />$_4site = 'not yet'; // valid; starts with an underscore<br />$t?yte = 'mansikka'; // valid; '洄 is (Extended) ASCII 228.<br />?>
PHP 3 中,變數總是傳值賦值。那也就是說,當你將一個運算式的值賦予一個變數時,整個原始運算式的值被賦值到目標變數。這意味著,例如,當一個變數的值賦予另外一個變數時,改變其中一個變數的值,將不會影響到另外一個變數。
PHP 4 提供了另外一種方式給變數賦值:傳地址賦值。這意味著新的變數簡單的引用(換言之,“成為其別名” 或者 “指向”)了原始變數。改動新的變數將影響到原始變數,反之亦然。這同樣意味著其中沒有執行複製操作;因而,這種賦值操作更加快速。儘管如此,任何提速的操作只有在緊密迴圈或者大數組或者對象才可能被注意到。
使用傳地址賦值,簡單地追加一個(&)符號到將要賦值的變數前(源變數)。例如,下列代碼片斷兩次輸出‘My name is Bob’:
<?php<br />$foo = 'Bob'; // Assign the value 'Bob' to $foo<br />$bar = &$foo; // Reference $foo via $bar.<br />$bar = "My name is $bar"; // Alter $bar...<br />echo $bar;<br />echo $foo; // $foo is altered too.<br />?>
需要注意的是只有命名變數才可以傳地址賦值,這一點非常重要。
<?php<br />$foo = 25;<br />$bar = &$foo; // This is a valid assignment.<br />$bar = &(24 * 7); // Invalid; references an unnamed expression.</p><p>function test()<br />{<br /> return 25;<br />}</p><p>$bar = &test(); // Invalid.<br />?>
二、預定義變數
PHP 提供了大量的預定義變數。由於許多變數依賴於啟動並執行伺服器的版本和設定,及其它因素,所以並沒有詳細的說明文檔。一些預定義變數在 PHP 以命令列形式運行時並不生效。
警告:PHP 4.2.0 以及後續版本中,PHP 指令 register_globals 的預設值為 off。這是 PHP 的一個主要變化。讓 register_globals 的值為 off 將影響到預定義變數集在全域範圍內的有效性。例如,為了得到 DOCUMENT_ROOT 的值,你將必須使用 $_SERVER['DOCUMENT_ROOT'] 代替 $DOCUMENT_ROOT,又如,使用 $_GET['id'] 來代替 $id 從 URL http://www.example.com/test.php?id=3 中擷取 id 值,亦或使用 $_ENV['HOME'] 來代替 $HOME 擷取環境變數 HOME 的值。 可變變數: 超級全域變數不能被用作可變變數.
如果某些 variables_order 中的變數沒有設定,它們的對應的 PHP 預定義數組也是空的。
2.1 PHP的超全域變數
$GLOBALS
包含一個引用指向每個當前指令碼的全域範圍內有效變數。該數組的鍵標為全域變數的 名稱。從 PHP 3 開始存在 $GLOBALS 數組。
$_SERVER
變數由 Web 服務器設定或者直接與當前指令碼的執行環境相關聯。類似於舊數組 $HTTP_SERVER_VARS 數組(依然有效,但反對使用)。
$_GET
經由 HTTP GET 方法提交至指令碼的變數。類似於舊數組 $HTTP_GET_VARS 數組(依然有效,但反對使用)。
$_POST
經由 HTTP POST 方法提交至指令碼的變數。類似於舊數組 $HTTP_POST_VARS 數組(依然有效,但反對使用)。
$_COOKIE
經由 HTTP Cookies 方法提交至指令碼的變數。類似於舊數組 $HTTP_COOKIE_VARS 數組(依然有效,但反對使用)。
$_FILES
經由 HTTP POST 檔案上傳而提交至指令碼的變數。類似於舊數組 $HTTP_POST_FILES 數組(依然有效,但反對使用)。
$_ENV
執行環境提交至指令碼的變數。類似於舊數組 $HTTP_ENV_VARS 數組(依然有效,但反對使用)。
$_REQUEST
經由 GET,POST 和 COOKIE 機制提交至指令碼的變數,因此該數組並不值得信任。所有包含在該數組中的變數的存在與否以及變數的順序均按照 php.ini 中的 variables_order 配置指示來定義。該數組沒有直接類比 PHP 4.1.0 的早期版本。
注意:自 PHP 4.3.0 起,$_FILES 中的檔案資訊不再存在於 $_REQUEST 中。
警告:當運行於命令列模式時,這個數組將不會包含 argv 和 argc 入口;它們已經存在於數組 $_SERVER 中。
三、變數範圍
變數的範圍即它定義的上下文背景(譯者:說白了,也就是它的生效範圍)。大部分的 PHP 變數只有一個單獨的範圍。這個單獨的範圍跨度同樣包含了 include 和 require 引入的檔案。範例:
<?php<br />$a = 1;<br />include "b.inc";<br />?>
這裡變數 $a 將會在包含檔案 b.inc 中生效。但是,在使用者自訂函數中,一個局部函數範圍將被引入。任何用於函數內部的變數按預設情況將被限制在局部函數範圍內。範例:
<?php<br />$a = 1; /* global scope */</p><p>function Test()<br />{<br /> echo $a; /* reference to local scope variable */<br />}</p><p>Test();<br />?>
這個指令碼不會有任何輸出,因為 echo 語句引用了一個局部版本的變數 $a,而且在這個範圍內,它並沒有被賦值。你可能注意到 PHP 的全域變數和 C 語言有一點點不同,在 C 語言中,全域變數在函數中自動生效,除非被局部變數覆蓋。這可能引起一些問題,有些人可能漫不經心的改變一個全域變數。PHP 中全域變數在函數中使用時必須申明為全域。
3.1 global關鍵字
代碼1:使用global關鍵字
<?php<br />$a = 1;<br />$b = 2;</p><p>function Sum()<br />{<br /> global $a, $b;</p><p> $b = $a + $b;<br />}</p><p>Sum();<br />echo $b;<br />?>
以上指令碼的輸出將是 "3"。在函數中申明了全域變數 $a 和 $b,任何變數的所有引用變數都會指向到全域變數。對於一個函數能夠申明的全域變數的最大個數,PHP 沒有限制。
在全域範圍內訪問變數的第二個辦法,是用特殊的 PHP 自訂 $GLOBALS 數組。前面的例子可以寫成:
代碼2:使用 $GLOBALS 替代 global
<?php<br />$a = 1;<br />$b = 2;</p><p>function Sum()<br />{<br /> $GLOBALS["b"] = $GLOBALS["a"] + $GLOBALS["b"];<br />}</p><p>Sum();<br />echo $b;<br />?>
在 $GLOBALS 數組中,每一個變數為一個元素,鍵名對應變數名,值變數的內容。$GLOBALS 之所以在全域範圍記憶體在,是因為 $GLOBALS 是一個超全域變數。以下範例顯示了超全域變數的用處:
代碼3:示範超全域變數和範圍的例子
<?php<br />function test_global()<br />{<br /> // 大多數的預定義變數並不 "super",它們需要用 'global' 關鍵字來使它們在函數的本地地區中有效。<br /> global $HTTP_POST_VARS;</p><p> print $HTTP_POST_VARS['name'];</p><p> // Superglobals 在任何範圍內都有效,它們並不需要 'global' 聲明。Superglobals 是在 PHP 4.1.0 引入的。<br /> print $_POST['name'];<br />}<br />?>
3.2 使用靜態變數
變數範圍的另一個重要特性是靜態變數(static variable)。靜態變數僅在局部函數域中存在,但當程式執行離開此範圍時,其值並不丟失。看看下面的例子:
代碼1:示範需要靜態變數的例子
<?php<br />function Test ()<br />{<br /> $a = 0;<br /> echo $a;<br /> $a++;<br />}<br />?>
本函數沒什麼用處,因為每次調用時都會將 $a 的值設為 0 並輸出 "0"。將變數加一的 $a++ 沒有作用,因為一旦退出本函數則變數 $a 就不存在了。要寫一個不會丟失本次計數值的計數函數,要將變數 $a 定義為靜態:
代碼2:使用靜態變數的例子
<?php<br />function Test()<br />{<br /> static $a = 0;<br /> echo $a;<br /> $a++;<br />}<br />?>
現在,每次調用 Test() 函數都會輸出 $a 的值並加一。
靜態變數也提供了一種處理遞迴函式的方法。遞迴函式是一種調用自己的函數。寫遞迴函式時要小心,因為可能會無窮遞迴下去。必須確保有充分的方法來中止遞迴。一下這個簡單的函數遞迴計數到 10,使用靜態變數 $count 來判斷何時停止:
代碼3:靜態變數與遞迴函式
<?php<br />function Test()<br />{<br /> static $count = 0;</p><p> $count++;<br /> echo $count;<br /> if ($count < 10) {<br /> Test ();<br /> }<br /> $count--;<br />}<br />?>
注: 靜態變數可以按照上面的例子聲明。如果在聲明中用運算式的結果對其賦值會導致解析錯誤。
代碼4:聲明靜態變數
<?php<br />function foo(){<br /> static $int = 0; // correct<br /> static $int = 1+2; // wrong (as it is an expression)<br /> static $int = sqrt(121); // wrong (as it is an expression too)</p><p> $int++;<br /> echo $int;<br />}<br />?>
3.3 全域和靜態變數的引用
在 Zend 引擎 1 代,驅動了 PHP4,對於變數的 static 和 global 定義是以 references 的方式實現的。例如,在一個函數域內部用 global 語句匯入的一個真正的全域變數實際上是建立了一個到全域變數的引用。這有可能導致預料之外的行為,如以下例子所示範的:
<?php<br />function test_global_ref() {<br /> global $obj;<br /> $obj = &new stdclass;<br />}</p><p>function test_global_noref() {<br /> global $obj;<br /> $obj = new stdclass;<br />}</p><p>test_global_ref();<br />var_dump($obj);<br />test_global_noref();<br />var_dump($obj);<br />?>
執行以上例子會導致如下輸出:
NULLobject(stdClass)(0) {}
類似的行為也適用於 static 語句。引用並不是靜態地儲存的:
<?php<br />function &get_instance_ref() {<br /> static $obj;</p><p> echo "Static object: ";<br /> var_dump($obj);<br /> if (!isset($obj)) {<br /> // 將一個引用賦值給靜態變數<br /> $obj = &new stdclass;<br /> }<br /> $obj->property++;<br /> return $obj;<br />}</p><p>function &get_instance_noref() {<br /> static $obj;</p><p> echo "Static object: ";<br /> var_dump($obj);<br /> if (!isset($obj)) {<br /> // 將一個對象賦值給靜態變數<br /> $obj = new stdclass;<br /> }<br /> $obj->property++;<br /> return $obj;<br />}</p><p>$obj1 = get_instance_ref();<br />$still_obj1 = get_instance_ref();<br />echo "/n";<br />$obj2 = get_instance_noref();<br />$still_obj2 = get_instance_noref();<br />?>
執行以上例子會導致如下輸出:
Static object: NULLStatic object: NULLStatic object: NULLStatic object: object(stdClass)(1) { ["property"]=> int(1)}
上例示範了當把一個引用賦值給一個靜態變數時,第二次調用 &get_instance_ref() 函數時其值並沒有被記住。
四、可變變數
有時候使用可變變數名是很方便的。就是說,一個變數的變數名可以動態設定和使用。一個普通的變數通過聲明來設定,例如:
<?php<br />$a = "hello";<br />?>
一個可變變數擷取了一個普通變數的值作為這個可變變數的變數名。在上面的例子中 hello 使用了兩個貨幣符號($)以後,就可以作為一個可變變數的變數了。例如:
<?php<br />$$a = "world";<br />?>
這時,兩個變數都被定義了:$a 的內容是“hello”並且 $hello 的內容是“world”。因此,可以表述為:
<?php<br />echo "$a ${$a}";<br />?>
以下寫法更準確並且會輸出同樣的結果:
<?php<br />echo "$a $hello";<br />?>
它們都會輸出:hello world。
要將可變變數用於數組,必須解決一個模稜兩可的問題。這就是當寫下 $$a[1] 時,解析器需要知道是想要 $a[1] 作為一個變數呢,還是想要 $$a 作為一個變數並取出該變數中索引為 [1] 的值。解決此問題的文法是,對第一種情況用 ${$a[1]},對第二種情況用 ${$a}[1]。
注意可變變數不能用於 PHP 的超全域變數數組。這意味著不能這樣用:${$_GET}。 如果想要一種處理超全域變數和老的 HTTP_*_VARS 的方法,應該嘗試引用它們。
五、PHP 的外部變數5.1 HTML 表單(GET 和 POST)
當一個表單體交給 PHP 指令碼時,表單中的資訊會自動在指令碼中可用。有很多方法訪問此資訊,例如:
代碼1:一個簡單的 HTML 表單
<form action="foo.php" method="POST"><br /> Name: <input type="text" name="username"><br><br /> Email: <input type="text" name="email"><br><br /> <input type="submit" name="submit" value="Submit me!"><br /></form><br />
根據特定的設定和個人的喜好,有很多種方法訪問 HTML 表單中的資料。例如:
代碼2: 從一個簡單的 POST HTML 表單訪問資料
<?php<br />// 自 PHP 4.1.0 起可用</p><p> print $_POST['username'];<br /> print $_REQUEST['username'];</p><p> import_request_variables('p', 'p_');<br /> print $p_username;</p><p>// 自 PHP 3 起可用。自 PHP 5.0.0 起,這些較長的預定義變數<br />// 可用 register_long_arrays 指令關閉。</p><p> print $HTTP_POST_VARS['username'];</p><p>// 如果 PHP 指令 register_globals = on 時可用。不過自<br />// PHP 4.2.0 起預設值為 register_globals = off。<br />// 不提倡使用/依賴此種方法。</p><p> print $username;<br />?><br />
使用 GET 表單也類似,只不過要用適當的 GET 預定義變數。GET 也適用於 QUERY_STRING(URL 中在“?”之後的資訊)。因此,舉例說,http://www.example.com/test.php?id=3 包含有可用 $_GET['id'] 訪問的 GET 資料。
註:注: 超全域變數數組,和 $_POST 以及 $_GET 一樣,自 PHP 4.1.0 起可用。
注: magic_quotes_gpc 配置指令影響到 Get,Post 和 Cookie 的值。如果開啟,值 (It's "PHP!") 會自動轉換成 (It/'s /"PHP!/")。資料庫的插入就需要轉義。
代碼3:更複雜的表單變數
<?php<br />if (isset($_POST['action']) && $_POST['action'] == 'submitted') {<br /> print '<pre>';</p><p> print_r($_POST);<br /> print '<a href="'. $_SERVER['PHP_SELF'] .'" mce_href="'. $_SERVER['PHP_SELF'] .'">Please try again</a>';</p><p> print '</pre>';<br />} else {<br />?><br /><form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"><br /> Name: <input type="text" name="personal[name]"><br><br /> Email: <input type="text" name="personal[email]"><br><br /> Beer: <br><br /> <select multiple name="beer[]"><br /> <option value="warthog">Warthog</option><br /> <option value="guinness">Guinness</option><br /> <option value="stuttgarter">Stuttgarter Schwabenbr漉</option><br /> </select><br><br /> <input type="hidden" name="action" value="submitted"><br /> <input type="submit" name="submit" value="submit me!"><br /></form><br /><?php<br />}<br />?>
在 PHP 3 中,變數使用中的數組僅限於一維數組。在 PHP 4 中,沒有此種限制。
5.2 HTML 表單(GET 和 POST)
當提交表單時,可以用一幅映像代替標準的提交按鈕,用類似這樣的標記:
<input type="image" src="image.gif" mce_src="image.gif" name="sub"><br />
當使用者點擊到映像中的某處時,相應的表單會被傳送到伺服器,並加上兩個變數 sub_x 和 sub_y。它們包含了使用者點擊映像的座標。有經驗的使用者可能會注意到被瀏覽器發送的實際變數名包含的是一個點而不是底線,但 PHP 自動將點轉換成了底線。
5.3 HTTP Cookies
PHP 透明地支援 Netscape 規範定義中的 HTTP cookies。Cookies 是一種在遠端瀏覽器端儲存資料並能追蹤或識別再次訪問的使用者的機制。可以用 setcookie() 函數設定 cookies。Cookies 是 HTTP 資訊頭中的一部分,因此 SetCookie 函數必須在向瀏覽器發送任何輸出之前調用。對於 header() 函數也有同樣的限制。Cookie 資料會在相應的 cookie 資料數組中可用,例如 $_COOKIE,$HTTP_COOKIE_VARS 和 $_REQUEST。
如果要將多個值賦給一個 cookie 變數,必須將其賦成數組。例如:
<?php<br /> setcookie("MyCookie[foo]", "Testing 1", time()+3600);<br /> setcookie("MyCookie[bar]", "Testing 2", time()+3600);<br />?>
這將會建立兩個單獨的 cookie,儘管 MyCookie 在指令碼中是一個單一的數組。如果想在僅僅一個 cookie 中設定多個值,考慮先在值上使用 serialize() 或 explode()。
注意在瀏覽器中一個 cookie 會替換掉上一個同名的 cookie,除非路徑或者域不同。因此對於購物框程式可以保留一個計數器並一起傳遞,例如:
代碼1:一個 setcookie() 的樣本
<?php<br />if (isset($_COOKIE['count'])) {<br /> $count = $_COOKIE['count'] + 1;<br />} else {<br /> $count = 1;<br />}<br />setcookie("count", $count, time()+3600);<br />setcookie("Cart[$count]", $item, time()+3600);<br />?>
5.4 變數中的名
通常,PHP 不會改變傳遞給指令碼中的變數名。然而應該注意到點(dot,period,full stop)不是 PHP 變數名中的合法字元。至於原因,看看:
<?php<br />$varname.ext; /* 非法變數名 */<br />?>
這時,解析器看到是一個名為 $varname 的變數,後面跟著一個字串串連運算子,後面跟著一個裸字串(例如沒有加引號的字串,且不匹配任何已知的健名或保留字)'ext'。很明顯這不是想要的結果。
出於此原因,要注意 PHP 將會自動將變數名中的點替換成底線。
因為 PHP 會判斷變數類型並在需要時進行轉換(通常情況下),因此在某一時刻給定的變數是何種類型並不明顯。PHP 包括幾個函數可以判斷變數的類型,例如:gettype(),is_array(),is_float(),is_int(),is_object() 和 is_string()。