搞定PHP面試 - 變數知識點整理
一、變數的定義
1. 變數的命名規則
變數名可以包含字母、數字、下劃線,不能以數字開頭。
$Var_1 = 'foo'; // 合法
$var1 = 'foo'; // 合法
$_var1 = 'foo'; // 合法
$Var-1 = 'foo'; // 非法,不能包含 -
$1_var = 'foo'; // 非法,不能以數字開頭
在此所說的字母是 a-z,A-Z,以及 ASCII 字元從 127 到 255(0x7f-0xff)。
因此實際上使用中文變數名也是合法的。
甚至使用中文的標點符號作為變數名都是合法的。
只是一般都不推薦這樣用。
$姓名 = 'foo'; // 合法 $?。…… = 'foo'; // 合法。
變數名區分大小寫
$var = 'Bob';
$Var = 'Joe';
echo "$var, $Var"; // 輸出 "Bob, Joe"
$this 是一個特殊的變數,它不能被賦值
$this = 'foo'; // Fatal error: Cannot re-assign $this
2. 變數的賦值
變數的引用賦值與傳值賦值詳情傳送門: 變數的引用賦值與傳值賦值
傳值賦值
變數預設總是傳值賦值。那也就是說,當將一個表示式的值賦予一個變數時,整個原始表示式的值被賦值到目標變數。
這意味著,例如,當一個變數的值賦予另外一個變數時,改變其中一個變數的值,將不會影響到另外一個變數。
$foo = 'Bob'; // 將 'Bob' 賦給 $foo
$bar = $foo; // 通過 $foo 傳值賦值給 $bar
$bar = 'Jack'; // 修改 $bar 變數
echo $foo; // $foo 的值未改變,依然是 'Bob'
引用賦值
引用賦值,就是新的變數簡單的引用(換言之,“成為其別名” 或者 “指向”)了原始變數。
改動新的變數將影響到原始變數,反之亦然。
使用引用賦值,只需要將一個 &
符號加到將要賦值的變數前(源變數)
$foo = 'Bob'; // 將 'Bob' 賦給 $foo $bar = &$foo; // 通過 $bar 引用 $foo $bar = 'Jack'; // 修改 $bar 變數 echo $foo; // $foo 的值也被修改為 'Jack'
只有有名字的變數才可以引用賦值
$foo = 25;
$bar = &$foo; // 合法的賦值
$bar = &(24 * 7); // 非法; 引用沒有名字的表示式
function test()
{
return 25;
}
$bar = &test(); // 非法
3.變數的初始化
雖然在 PHP 中並不需要初始化變數,但對變數進行初始化是個好習慣。
未初始化的變數的預設值
未初始化的變數具有其型別的預設值。
- 布林型別的變數預設值是
FALSE
- 整形和浮點型變數預設值是
0
- 字串型變數預設值是空字串
""
- 陣列變數的預設值是空陣列
array()
4. 可變變數
可變變數是指變數的變數名可以動態的設定和使用。
一個可變變數獲取了一個普通變數的值作為這個可變變數的變數名。在下面的例子中 hello 使用了兩個美元符號($
)以後,就可以作為一個可變變數的變量了。
$a = 'hello';
$$a = 'world';
這時,兩個變數都被定義了:$a
的內容是“hello”並且 $hello 的內容是“world”。
因此,以下語句:
echo "$a ${$a}";
與以下語句輸出完全相同的結果:
echo "$a $hello";
它們都會輸出:hello world。
可變變數用於陣列
要將可變變數用於陣列,必須解決一個模稜兩可的問題。
這就是當寫下 $$a[1]
時,解析器需要知道是想要 $a[1]
作為一個變數呢,還是想要 $ $a
作為一個變數並取出該變數中索引為 [1]
的值。
解決此問題的語法是,對第一種情況用 ${$a[1]}
,對第二種情況用 ${$a}[1]
。
可變變數用於類
類的屬性也可以通過可變屬性名來訪問。可變屬性名將在該呼叫所處的範圍內被解析。
例如,對於 $foo->$bar
表示式,則會在本地範圍來解析 $bar 並且其值將被用於 $foo 的屬性名。
對於 $bar
是陣列單元時也是一樣。
也可使用花括號{}
來給屬性名清晰定界。
最有用是在屬性位於陣列中,或者屬性名包含有多個部分或者屬性名包含有非法字元時(例如來自 json_decode()
或 SimpleXML
)。
將一個json格式的字串轉換成php物件:
$string = '{"os-version":"10.3.1","1day":24}';
$obj = json_decode($string);
print_r($obj);
輸出結果:
stdClass Object
(
[os-version] => 10.3.1
[1day] => 24
)
此時若想訪問物件$obj 中的 os-version
屬性或1day
屬性,若直接使用 $obj->os-version
,$obj->1day
訪問的話一定會報錯。
正確的訪問方式:
echo $obj->{"os-version"};
echo '<br/>';
echo $obj->{"1day"};
輸出結果:
10.3.1
24
二、變數的作用域和靜態變數
1. 變數的作用域
變數的作用域也稱變數的範圍,即它定義的上下文背景(也就是它的生效範圍)。
php變數的範圍跨度同樣包含了include和require引入的檔案。
區域性變數
在使用者自定義函式中,將引入一個區域性函式範圍。任何用於函式內部的變數的作用域都將被限制在區域性函式範圍內。例如:
$outer = 'str'; /* 全域性範圍 */
function myfunc()
{
echo $outer; /* 對區域性範圍變數的引用 */
}
myfunc();
這個指令碼不會有任何輸出,因為 echo 語句引用了一個區域性版本的變數 $outer
,而且在這個範圍內,它並沒有被賦值。
全域性變數
global關鍵字
$outer = 'str'; // 全域性
function myfunc()
{
global $outer;
echo $outer; // 區域性
}
myfunc();
這個指令碼會輸出 str
。在函式中使用global關鍵字聲明瞭全域性變數 $a
和 $b
之後,對任一變數的所有引用都會指向其全域性版本。對於一個函式能夠宣告的全域性變數的最大個數,PHP 沒有限制。
$GLOBALS超全域性陣列
$GLOBALS
— 引用全域性作用域中可用的全部變數
$outer = 'str'; // 全域性
function myfunc()
{
echo $GLOBALS['outer'];
}
myfunc();
這個指令碼會輸出 str
。$GLOBALS
是一個關聯陣列,每一個變數為一個元素,鍵名對應變數名,值對應變數的內容。$GLOBALS
之所以在全域性範圍內存在,是因為 $GLOBALS
是一個超全域性變數。
PHP 中的許多預定義變數都是“超全域性的”,這意味著它們在一個指令碼的全部作用域中都可用。在函式或方法中無需執行 global $variable; 就可以訪問它們。
這些超全域性變數是:
$GLOBALS
— 超全域性變數是在全部作用域中始終可用的內建變數$_SERVER
— 伺服器和執行環境資訊$_GET
— HTTP GET 變數$_POST
— HTTP POST 變數$_FILES
— HTTP 檔案上傳變數$_COOKIE
— HTTP Cookies$_SESSION
— Session 變數$_REQUEST
— HTTP Request 變數。預設情況下包含了 $_GET
,$_POST
和 $_COOKIE
的陣列。$_ENV
— 環境變數
2. 靜態變數
變數範圍的另一個重要特性是靜態變數(static variable)。
靜態變數僅在區域性函式域中存在,但當程式執行離開此作用域時,其值並不會消失。
靜態變數的特點
1.使用static關鍵字修飾
2.靜態宣告是在編譯時解析的
3.僅初始化一次
4.初始化時需要賦值
5.每次執行函式該值會保留
6.static修飾的變數是區域性的,僅在函式內部有效
7.可以記錄函式的呼叫次數,從而可以在某些條件下終止遞迴。
function myFunc()
{
static $a = 1;
echo $a++;
}
myFunc(); // 1
myFunc(); // 2
myFunc(); // 3
變數 $a
僅在第一次呼叫 myFunc()
函式時被初始化,之後每次呼叫 myFunc()
函式都會輸出 $a 的值並加1。
宣告靜態變數時不能用表示式的結果對其賦值
function foo(){
static $int = 0; // 正確
static $int = 1+2; // 錯誤 (使用表示式的結果賦值)
static $int = sqrt(121); // 錯誤 (使用表示式的結果賦值)
echo $int++;
}
靜態變數與遞迴函式
靜態變數提供了一種處理遞迴函式的方法。
遞迴函式是一種呼叫自己的函式。寫遞迴函式時要小心,因為可能會無窮遞迴下去。必須確保有充分的方法來中止遞迴。
以下這個簡單的函式遞迴計數到 10,使用靜態變數 $count 來判斷何時停止:
function test()
{
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
test();
}
$count--;
}
3. 例項分析
寫出如下程式的輸出結果
$count = 5;
function get_count()
{
static $count;
return $count++;
}
echo $count;
++$count;
echo get_count();
echo get_count();
第8行 echo $count;
輸出 5
第9行 ++$count;
,此時 $count
的值為 6
第11行 echo get_count();
,第一次呼叫 get_count()
函式
function get_count()
{
// 宣告靜態變數 $count,由於為賦值,所以其值為 NULL
static $count;
// $count++,先返回 $count 的值,後自增。因此,返回值為 NULL。
// NULL 自增後的值為 1,因此,自增後的 $count = 1
return $count++;
}
第一次呼叫 get_count()
的返回值為 NULL,而 echo NULL;
什麼都不會輸出。
第12行 echo get_count();
,第二次呼叫 get_count()
函式
function get_count()
{
// 第二次呼叫時,該行不會執行
static $count;
// 此前 $count = 1,$count++,先返回 $count 的值,後自增。因此,返回值為 1。
return $count++;
}
第一次呼叫 get_count()
的返回值為 1,而 echo get_count();
輸出 1
。