PHP 教學 - 變數 (Variables)
介紹 PHP 變數的用法,包含命名、指派 (assign)、宣告、變數範圍、預定義變數、全域變數、可變變數 (Variable variables)、POST、GET、REQUEST 和 COOKIE。
基礎
命名規則
變數是由錢號 ($
) 開始,後面接著變數名稱,變數名稱有大小寫之分。變數名稱可以是英文字母、數字、底線和十六進位制為 0x7f - 0xff
的字元所組成,但是第一個字元不能是以數字開頭。正規表示法如下:
1 | [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]* |
一些宣告範例如下:
1 | $User = 'dindin'; |
指派
變數的指派 (assign) 一般都是傳值的方式複製一份,而物件型別的變數除外。PHP 中可使用 (&
) 符號讓其他型別的變數也能以傳址的方式指派,且只有變數才能使用 (&
) 傳址。
1 | $fool = 'dindin'; |
宣告
PHP 中的變數並不需要特別宣告,所有未宣告的變數都視為 NULL,變數的型別也會直接依據指派的值來決定。
1 | var_dump($unset_var); // NULL |
預定義變數
PHP 有許多預先定義的變數,要注意不要使用到這些名稱作為自己的變數,例如 $_GET
、$_POST
…等。有哪些可使用的預定義變數和詳細說明,預計在之後的文章再做介紹。在 php.ini
中,有些設定與預定義變數有相關在此稍作說明。
register_globals
在 PHP 4 之前的版本,php.ini
設定中的 register_globals
預設為 on
,所以可以直接使用 $id
取得 http//localhost/index.php?id=1
的 id
值;PHP 4.2.0 之後 register_globals
則改為預設 off
,就必須使用 $_GET['id']
的方式來取得。不只是 GET 其他預定義變數例如 $_POST
、$_SERVER
…等,也是要用這種方式取值。基於安全性問題,並不建議開啟 register_globals
,一個攻擊範例如下:
1 | // 網址列傳遞參數 ?_SESSION[id]=1 |
register_long_arrays
在 PHP 5 之前,是使用 $HTTP_*_VARS
的方式去取值,對應於 $_*
,例如 $HTTP_GET_VARS
、$HTTP_POST_VARS
…等,分別對應於 $_GET
、$_POST
…等;在 PHP 5 之後,則改採用 $_*
的方式,若要使用舊的 $HTTP_*_VARS
的用法,可以將 register_long_arrays
設為 on
。
當 register_long_arrays
開啟時,$HTTP_*_VARS
與 $_*
並不是相同的物件,修改其中一個,對應的另一個並不會一起被修改到。另外,$_*
是屬於超級全域變數 (Superglobals),但 $HTTP_*_VARS
並不是。超級全域變數之後再做介紹。理論上關閉此功能的效能會比較好。
如果新的程式要跑在舊版的環境下,可以在程式開頭加入以下的程式碼來達到向下相容:
1 | if (!isset($_SERVER)) { |
變數範圍
基礎
程式中我們可能會在不同的位置,用到相同的變數名稱,表示不同的東西,如果變數沒有範圍就可能會互相干擾。所以在程式中,會有不同的變數範圍,當程式離開這個範圍之後,屬於此範圍的變數就會清除。PHP 中分為全域變數和區域變數,基本上依照下述的原則:
- 在
function
中的變數為區域變數。 include
中的變數範圍與呼叫include
的所在範圍相同。- 其他為全域變數。
1 | $num = 100; // 全域變數 |
inc.php
1 | var_dump($num); |
使用全域變數
要在區域範圍中使用全域變數可以使用以下兩種方法:
global
使用 global
關鍵字來宣告要使用的全域變數。以 global
關鍵字開頭,後面接著要使用的全域變數。
1 | $num = 55; |
$GLOBALS
使用預定義變數 $GLOBALS
來取得全域變數。$GLOBALS
是關聯式陣列,使用變數名稱做為索引值即可取得變數。
1 | $num = 55; |
static
另外有一個變數型態為靜態變數,使用 static
關鍵字來宣告,靜態變數會一直存在,直到程式結束。例如用在一個函式可能會重複被叫用,而想在每次叫用時使用同一個變數,就可以使用靜態變數。靜態變數有一些特性:
- 靜態變數的指派必須要直接給一個定值,不可以是運算、變數、函式結果和建立物件等來源。
- 重複的宣告靜態變數時,以最後一次宣告的值為初始值。
1 | $num = 100; |
常見問題
清除全域變數
在區域範圍中要清除全域變數時,要注意使用 unset()
函式和設為 null
的結果並不相同,範例如下:
1 | $num = 178; |
區域範圍傳址
在區域範圍中使用 global
關鍵字與 $GLOBALS
陣列方式去接另一個變數的位址時,會有不同的結果:
1 | $num = 100; |
造成上面兩個問題的原因相同,global
關鍵字的行為可以想成:建立一個區域變數,來源為全域變數的位址。例如,global $num;
相當於 $num = &$GLOBALS['num'];
。
可變變數
基礎
可變變數 (Variable variables,或變數的變數),意思是可以使用變動的內容來轉換為另一個變數的名稱使用,用法規則如下:
- 使用錢號 (
$
) 加上變數、常數或函式回傳值等來轉換,可以多重使用。 - 與字串中的變數類似,可使用大括號來明確標示出來源。
- 不能用在類別和函式中的超級全域變數和
$this
關鍵字。
1 | $user = "fool"; |
其他用法
利用此用法,甚至可以使用不合法的變數命名作為變數名稱:
1 | $var = "7-11"; |
外部來源變數
透過表單、網址列傳值或 Cookie 等方式,可以從使用者端接受到一些資料。這些資料依據來源可以從不同的預定義變數中取得,包括 $_POST
、$_GET
、$_COOKIE
、$_REQUEST
和 $_FILES
。
POST
基礎
$_POST
與 $_FILES
是透過表單的 POST Method 來送出,例如有個 HTML 的表單如下:
1 | <form action="test.php" method="post" enctype="multipart/form-data"> |
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']
的陣列:
1 | <form action="test.php" method="post"> |
其他用法
POST 的資料也可以使用讀檔的方式取得,可以利用 file_get_contents()
函式,讀取虛擬的檔案路徑 php://input
來取得 POST 資料,而資料會以類似查詢字串 (參考下個章節) 的格式呈現。
1 | <form action="test.php" method="post" > |
查詢字串
查詢字串 (Query string) 是透過網址列傳值的方式送出,或者利用 method
為 get
的 form
送出。網址列傳址的使用方式如下:
- 在URL的後方加上問號 (
?
),作為使用查詢字串的開頭。 - 後面則接上
key=value
的變數內容。 - 變數間使用
&
隔開。- 在 URL 的後方加上問號 (
?
),作為使用查詢字串的開頭。 - 後面則接上
key=value
的變數內容。 - 變數間使用
&
隔開。
- 在 URL 的後方加上問號 (
例如: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']
的陣列。
Cookie
Cookie 是存放在使用者的瀏覽器,除了 JavaScript 外,也可以由 PHP 的 setcookie()
函式去設定,然後使用 $_COOKIE
去取得。
雖然 Cookie 是透過 JavaScript 或 PHP 的函式去產生,但他與 $_GET
和 $_POST
都是由使用者端送出,資料是可以被修改的,不適合拿來作為權限檢驗等用途。
Request
$_GET
、$_POST
和 $_COOKIE
等使用者送出的請求 (Request),會自動合併成 $_REQUEST
陣列,至於哪些資料要合併,則在 php.ini
中的 request_order
或 variables_order
設定,在 PHP 5.3.0 之後預設為 "GP"
,也就是包含 $_GET
和 $_POST
,且 $_POST
順序在 $_GET
之後,亦即當有重複變數時,由 $_POST
蓋掉 $_GET
。可以設定的值如下:
- E: $_ENV
- G: $_GET
- P: $_POST
- C: $_COOKIE
- S: $_SERVER
例如:request_order = "CGP"
表示 $_REQUEST
包含 $_COOKIE
、$_GET
和 $_POST
。
常見問題
變數名稱轉換
在送出的變數名稱如果包含點 (.
)、左中括號 ([
)、空白和 ASCII 字元 128 到 159 會被轉換成底線 (_
),而左中括號一旦出現後之後就不會再轉換,例如:
1 | <form action="hello.php" method="post"> |
選單多選
HTML 選單 (Select) 使用多選時,名稱必須要使用 name[]
的格式才能正確取得多選陣列,例如:
1 | <form action="hell.php" method="post"> |
圖形送出按鈕
有時候我們會利用圖片按鈕 (input type="image"
) 來取代表單的送出按鈕,在送出後會得到 name_x
和 name_y
的變數,分別表示點擊時滑鼠在圖片的座標位置。其中 value
會依據瀏覽器不同,而有不同結果,例如:在Firefox 會多送出 name=value
的資料,但 IE 則不會送出。
1 | <form action="test.php" method="post" > |
延伸閱讀
上一篇 PHP 教學 - 資料型態 (Data Type) - 下
下一篇 PHP 教學 - 常數 (Constants)