PHP教學 - 變數(Variables)
介紹PHP變數的用法,包含命名、指派(assign)、宣告、變數範圍、預定義變數、全域變數、可變變數(Variable variables)、POST、GET、REQUEST和COOKIE。
1. 基礎
1.1 命名規則
變數是由錢號($)開始,後面接著變數名稱,變數名稱有大小寫之分。變數名稱可以是英文字母、數字、底線和十六進位制為0x7f-0xff的字元所組成,但是第一個字元不能是以數字開頭。正規表示法如下:
[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
一些宣告範例如下:
?php $User = 'dindin'; $user = 'lala'; echo "$User, $user"; // 大小寫不同: dindin, lala //$3m = '300cm'; // parse error, 不能是數字開頭 $_55 = 66; // 有效的 $lälä = '偽物'; // 有效的, 但必須存檔為UTF-8, 否則會Parse error, 'ä' ASCII 228 ?>
1.2 指派
變數的指派(assign)一般都是傳值的方式複製一份,而物件型別的變數除外。PHP中可使用(&)符號讓其他型別的變數也能以傳址的方式指派,且只有變數才能使用(&)傳址。
<?php
$fool = 'dindin';
$bar = &$fool;
$bar = "My name is {$bar}.";
echo $bar; // My name is dindin.
echo $fool; // My name is dindin.
//$bar = &(24 * 7); // Parse error, 只有變數才能用&
?>
1.3 宣告
PHP中的變數並不需要特別宣告,所有未宣告的變數都視為NULL,變數的型別也會直接依據指派的值來決定。
<?php
var_dump($unset_var); // NULL
$unset_str .= '30cm';
var_dump($unset_str); // string(4) "30cm"
$unset_int += 178;
var_dump($unset_int); // int(178)
$unset_float += 169.99;
var_dump($unset_float); // float(169.99)
$unset_arr[3] = 9527;
var_dump($unset_arr); // array(1) { [3]=> int(9527) }
$unset_obj->fool = 'dindin';
var_dump($unset_obj); // object(stdClass)#1 (1) { ["fool"]=> string(6) "dindin" }
?>
2. 預定義變數
PHP有許多預先定義的變數,要注意不要使用到這些名稱作為自己的變數,例如$_GET、$_POST...等。有哪些可使用的預定義變數和詳細說明,預計在之後的文章再做介紹。在php.ini中,有些設定與預定義變數有相關在此稍作說明。
2.1 register_globals
在
PHP4之前的版本,php.ini設定中的register_globals預設為on,所以可以直接使用$id
取得http//localhost/index.php?id=1的id值;PHP4.2.0之後register_globals則改為預設off,
就必須使用$_GET['id']的方式來取得。不只是GET其他預定義變數例如$_POST、$_SERVER...等,也是要用這種方式取值。基於安
全性問題,並不建議開啟register_globals,一個攻擊範例如下:
<?php // 網址列傳遞參數 ?_SESSION[id]=1 if(isset($_SESSION['id'])) echo "有登入"; // register_globals on, 判斷為true else echo "沒登入"; // register_globals off, 判斷為false ?>
2.2 register_long_arrays
在PHP5之前,是使
用$HTTP_*_VARS的方式去取值,對應於$_*,例如$HTTP_GET_VARS、$HTTP_POST_VARS...等,分別對應
於$_GET、$_POST...等;在PHP5之後,則改採用$_*的方式,若要使用舊的$HTTP_*_VARS的用法,可以將
register_long_arrays設為on。
當register_long_arrays開啟
時,$HTTP_*_VARS與$_*並不是相同的物件,修改其中一個,對應的另一個並不會一起被修改到。另外,$_*是屬於超級全域變數
(Superglobals),但$HTTP_*_VARS並不是。超級全域變數之後再做介紹。理論上關閉此功能的效能會比較好。
如果新的程式要跑在舊版的環境下,可以在程式開頭加入以下的程式碼來達到向下相容:
<?php
if (!isset($_SERVER))
{
$_GET = &$HTTP_GET_VARS;
$_POST = &$HTTP_POST_VARS;
$_ENV = &$HTTP_ENV_VARS;
$_SERVER = &$HTTP_SERVER_VARS;
$_COOKIE = &$HTTP_COOKIE_VARS;
$_REQUEST = array_merge($_GET, $_POST, $_COOKIE);
}
?>
3. 變數範圍
3.1 基礎
程式中我們可能會在不同的位置,用到相同的變數名稱,表示不同的東西,如果變數沒有範圍就可能會互相干擾。所以在程式中,會有不同的變數範圍,當程式離開這個範圍之後,屬於此範圍的變數就會清除。PHP中分為全域變數和區域變數,基本上依照下述的原則:
在function中的變數為區域變數。
include中的變數範圍與呼叫include的所在範圍相同。
其他為全域變數。
include中的變數範圍與呼叫include的所在範圍相同。
其他為全域變數。
<?php
$num = 100; // 全域變數
include("inc.php"); // int(100), inc.php中的範圍為全域
function func() {
var_dump($num); // NULL, 在func範圍中沒有$num
include("inc.php"); // NULL, inc.php中的範圍為func的區域
}
func();
function func2() {
var_dump($num);
$num = 200; // 區域變數, 不會影響全域的$num
}
func2(); // NULL, func2又為另一個區域
func2(); // NULL, 上次進入func2的$num在離開函式就清除
var_dump($num); // int(100)
include("inc.php"); // int(100)
if(true) {
$num2 = 300; // if中仍為全域變數
}
var_dump($num2); // int(300)
for($i=0;$i<5;$i++) {
$num3 = 400;
}
var_dump($i); // int(5)
?>
inc.php
<?php
var_dump($num);
?>
3.2 使用全域變數
要在區域範圍中使用全域變數可以使用以下兩種方法:
3.2-1 global
使用global關鍵字來宣告要使用的全域變數。以global關鍵字開頭,後面接著要使用的全域變數。
<?php
$num = 55;
$num2 = 66;
function func()
{
var_dump($num); // NULL
global $num, $num2;
var_dump($num); // int(55)
$num = $num2;
}
func();
var_dump($num); // int(66)
?>
3.2-2 $GLOBALS
使用預定義變數$GLOBALS來取得全域變數。$GLOBALS是關聯式陣列,使用變數名稱做為索引值即可取得變數。
<?php
$num = 55;
$num2 = 66;
function func()
{
var_dump($GLOBALS['num']); // int(55)
$GLOBALS['num'] = $GLOBALS['num2'];
}
func();
var_dump($num); // int(66)
?>
3.3 static
另外有一個變數型態為靜態變數,使用static關鍵字來宣告,靜態變數會一直存在,直到程式結束。例如用在一個函式可能會重複被叫用,而想在每次叫用時使用同一個變數,就可以使用靜態變數。靜態變數有一些特性:
靜態變數的指派必須要直接給一個定值,不可以是運算、變數、函式結果和建立物件等來源。
重複的宣告靜態變數時,以最後一次宣告的值為初始值。
重複的宣告靜態變數時,以最後一次宣告的值為初始值。
<?php
$num = 100;
function func() {
return 10;
}
function counter() {
static $count = 0;
$count++;
var_dump($count);
unset($count); // $count = NULL, 但沒有真正的被清除
static $count = 55; // 以最後宣告為初始值
// 以下皆為 parse error, 必須直接給定值
// static $count = new stdClass;
// static $count = 1 + 1;
// static $count = $GLOBALS['num'];
// static $count = func();
}
counter(); // int(56)
counter(); // int(57)
?>
3.4 常見問題
3.4-1 清除全域變數
在區域範圍中要清除全域變數時,要注意使用unset()函式和設為null的結果並不相同,範例如下:
<?php
$num = 178;
function func() {
global $num;
unset ($num);
}
function func2() {
global $num;
$num = null;
}
func();
var_dump($num); // int(178)
func2();
var_dump($num); // NULL
?>
3.4-2 區域範圍傳址
在區域範圍中使用global關鍵字與$GLOBALS陣列方式去接另一個變數的位址時,會有不同的結果:
<?php
$num = 100;
function func() {
global $num;
$num2 = 200;
$num = &$num2;
}
func();
var_dump($num); // int(100)
function func2() {
$num2 = 200;
$GLOBALS['num'] = &$num2;
}
func2();
var_dump($num); // int(200)
?>
造成3.4-1和3.4-2問題的原因相同,global關鍵字的行為可以想成:建立一個區域變數,來源為全域變數的位址。例如,global $num;相當於$num = &$GLOBALS['num'];。
4. 可變變數
4.1 基礎
可變變數(Variable variables,或變數的變數),意思是可以使用變動的內容來轉換為另一個變數的名稱使用,用法規則如下:
使用錢號($)加上變數、常數或函式回傳值等來轉換,可以多重使用。
與字串中的變數類似,可使用大括號來明確標示出來源。
不能用在類別和函式中的超級全域變數和$this關鍵字。
與字串中的變數類似,可使用大括號來明確標示出來源。
不能用在類別和函式中的超級全域變數和$this關鍵字。
<?php
$user = "fool";
$fool = "lala";
$lala = "黃色";
echo {$user}; // 黃色, 可以多重使用和大括號用法
function func($bar) {
var_dump(group['lala']); // NULL, 當成${$group['lala']}
var_dump(${$group}['lala']); // string(4) "黃色"
class Lala {
var $color = "黃色";
function func($bar) {
var_dump(var = "Always open";
var_dump($$var); // string(11) "Always open"
//var_dump($7-11); // parse error
var_dump(${"7-11"}); // string(11) "Always open"
?>
5. 外部來源變數
透過表單、網址列傳值或Cookie等方式,可以從使用者端接受到一些資料。這些資料依據來源可以從不同的預定義變數中取得,包括$_POST、$_GET、$_COOKIE、$_REQUEST和$_FILES。
5.1 POST
5.1-1 基礎
$_POST與$_FILES是透過表單的POST Method來送出,例如有個HTML的表單如下:
<form action="test.php" method="post" enctype="multipart/form-data"> 檔案: <input type="file" name="uploadFile"><br/> 描述: <input type="text" name="description"><br/> <input type="submit" name="submit" value="送出"> </form>
action為資料要送往的地方。method為使用POST或GET,設定為POST,則
資料從$_POST取得;若用GET則從$_GET取得。enctype="multipart/form-data"表示有包含檔案。上傳檔案必須要使
用POST,上傳的檔案使用$_FILES取得。Input欄位的name則為在陣列中的Key,例如上面的範例可得
到$_FILES['uploadFile']、$_POST['description']和$_POST['submit']等資料。
POST和上傳的檔案允許的大小限制可在php.ini中設定,分別為post_max_size和upload_max_filesize。
POST也可送出陣列,將input的命名為name[]的格式送出。例如下面會得到一個$_POST['id']的陣列:
<form action="test.php" method="post" >
<input type="hidden" name="fool" value="lala"><br/>
<input type="submit" name="submit" value="Post">
</form>
<?php
echo file_get_contents("php://input"); // fool=lala&submit=Post
?>
5.2 查詢字串
查詢字串(Query string)是透過網址列傳值的方式送出,或者利用method為get的form送出。網址列傳址的使用方式如下:
1. 在URL的後方加上問號(?),作為使用查詢字串的開頭。
2. 後面則接上key=value的變數內容。
3. 變數間使用&隔開。
2. 後面則接上key=value的變數內容。
3. 變數間使用&隔開。
在URL的後方加上問號(?),作為使用查詢字串的開頭。
後面則接上key=value的變數內容。
變數間使用&隔開。
後面則接上key=value的變數內容。
變數間使用&隔開。
例如:http://localhost/test.php?id=1&mode=delete,可得到$_GET['id']=1和$_GET['mode']='delete'的資料。
URL的長度一般限制最大為2048個字元,IE為2083個字元。
查詢字串也可以送出陣列,一樣使用name[]的方式送出例如:http://localhost/test.php?id[]=1&id[]=2,可以得到一個$_GET['id']的陣列
5.3 Cookie
Cookie是存放在使用者的瀏覽器,除了JavaScript外,也可以由PHP的setcookie()函式去設定,然後使用$_COOKIE去取得。
雖然Cookie是透過JavaScript或PHP的函式去產生,但他與$_GET和$_POST都是由使用者端送出,資料是可以被修改的,不適合拿來作為權限檢驗等用途。
5.4 Request
$_GET、$_POST
和$_COOKIE等使用者送出的請求(Request),會自動合併成$_REQUEST陣列,至於哪些資料要合併,則在php.ini中的
request_order或variables_order設定,在PHP5.3.0之後預設為"GP",也就是包含$_GET和$_POST,
且$_POST順序在$_GET之後,亦即當有重複變數時,由$_POST蓋掉$_GET。可以設定的值如下:
E: $_ENV
G: $_GET
P: $_POST
C: $_COOKIE
S: $_SERVER
G: $_GET
P: $_POST
C: $_COOKIE
S: $_SERVER
例如:request_order = "CGP" 表示$_REQUEST包含$_COOKIE、$_GET和$_POST。
5.5 常見問題
5.5-1 變數名稱轉換
在送出的變數名稱如果包含點(.)、左中括號([)、空白和ASCII字元128到159會被轉換成底線(_),而左中括號一旦出現後之後就不會再轉換,例如:
<form action="hello.php" method="post"> <input name="a b.c[d" value="dindin" type="hidden"> <input name="a b[c.d" value="lala" type="submit"> </form> <?php print_r($_POST); // Array ( [a_b_c_d] => dindin [a_b_c.d] => lala ) ?>
5.5-2 選單多選
HTML選單(Select)使用多選時,名稱必須要使用name[]的格式才能正確取得多選陣列,例如:
<form action="hell.php" method="post"> <select multiple="multiple" name="fools[]"> <option value="lala">Lala</option> <option value="dindin">Dindin</option> </select> <input name="submit" value="送出" type="submit"> </form>
5.5-3 圖形送出按鈕
有時候我們會利用圖片按鈕(input
type="image")來取代表單的送出按鈕,在送出後會得到name_x和name_y的變數,分別表示點擊時滑鼠在圖片的座標位置。其中
value會依據瀏覽器不同,而有不同結果,例如:在Firefox會多送出name=value的資料,但IE則不會送出。
<form action="test.php" method="post" >
<input type="image" name="submit" value="something" src="submit.gif">
</form>
<?php
print_r($_POST); // IE: Array ( [submit_x] => ... [submit_y] => ... )
// FF: Array ( [submit_x] => ... [submit_y] => ... [submit] => something)
?>
留言
張貼留言