具體方法
PHP 變數
PHP變數用於儲存字元、數字、數組甚至對象內容等,以便在我們需要的地方使用。
定義一個變數的文法:
$變數名 = 值;
使用變數的例子:
| 代碼如下 |
複製代碼 |
<?php $var_char = "你好!"; echo $var_char; ?> |
執行這段代碼輸出的結果是:
1 你好!
從這個例子可以看出,變數名以 $ 開始,標明這是一個變數。變數名以字母(a-z、A-Z)或者底線 _ 開始,後面可以跟任意字母或數字以及底線,但不能是空格。
如下這些變數名是有效:
$var_char
$varChar
$_varChar
$var_char5
提示
關於變數命名,我們建議變數名以標明其實際語意的組合為佳,如 $my_name 或 $myName 格式。
全域變數global
全域變數便是其中之一,當然這個觀點頗具爭議,有許多人還是建議禁用全域變數,使用不當對造成程式的可讀性很差!結構混亂,調試更是一頭霧水,但是不可否認他的便捷,這便是php為什麼會用全域變數global原因吧!…
今天就遇到了php 全域變數不起作用的問題.
先上一段簡單的代碼:
| 代碼如下 |
複製代碼 |
<?php $a = 0 ; function Test() { $a =1; } Test(); echo $a; ?> |
上面的代碼中輸出是0,那是因為函數體Test內$a變數被預設設定為局部變數,$a的範圍就是在Test內.修改代碼如下
| 代碼如下 |
複製代碼 |
<?php $a = 0 ; function Test() { global $a;//申明函數體Test內使用的$a變數為global全域變數 $a =1; } Test(); echo $a; ?> |
申明函數體Test內使用的$a變數為global全域變數後,使得$a的作用全域,所以輸出為1.
上面的執行個體只是基本的global全域變數知識,下面我們看看複雜點的:
| 代碼如下 |
複製代碼 |
//A.php 檔案 <?php function Test_Global() { include 'B.php'; Test(); } $a = 0 ; Test_Global(); echo $a; ?> //B.php 檔案 <?php function Test() { global $a;//申明函數體Sum內使用的$a變數為global全域變數 $a =1; } ?> |
為什麼輸出的卻是0?!!
在使用者自訂函數中,一個局部函數範圍將被引入。任何用於函數內部的變數按預設情況將被限制在局部函數範圍內(包括include 和 require 匯入的檔案內的變數)!
解釋:A.php檔案的內Test_Global是定義好的第三方函數,該函數用include匯入了B.php檔案內的$a的global全域變數,所以$a被限制在Test_Global局部函數範圍內,所以B.php檔案內的$a的作用範圍都在Test_Global內,而不是作用了整個A.php內….
解決方案:
1. 衝出局部函數//A.php 檔案
| 代碼如下 |
複製代碼 |
<?php function Test_Global() { Test(); } include 'B.php'; //將include 從局部Test_Global函數中移出 $a = 0 ; Test_Global(); echo $a; ?> //B.php 檔案 <?php function Test() { global $a; $a =1; } ?> |
2.優秀的訪問器
| 代碼如下 |
複製代碼 |
//A.php 檔案 <?php include 'B.php'; $a =0; Set_Global($a); echo $a; ?> //B.php 檔案 <?php function Set_Global(&$var) { $var=1; } ?>
|
php變數 引用函數 static變數
“無論怎樣聲明變數(按值或按引用),總之在PHP指令碼的任何位置都可以聲明變數。但是,聲明的位置會大大影響訪問變數的範圍。這個可訪問的範圍稱為範圍(scope)” –PHP與MySQL程式設計
在瞭解php變數之前,我們先看看段式記憶體管理架構的記憶體段的劃分。通常作業系統會將實體記憶體劃分為以下幾個邏輯段。
Text-Segment,這個段最大的特點就是唯讀。一般存放可執行代碼,也有可能常量也存放在這裡,比如字串常量
BSS-Segment,這裡存放了那些沒有初始化的變數。某種意義來講,沒有初始化的變數都是垃圾,不可用
Data-Segment,這裡存放了全域變數和靜態變數,直到指令碼運行結束,作業系統才會回收這裡的記憶體空間,變數亦會被銷毀。
Stack-Heap Segment 函數參數與本地變數(也稱局部變數)存放在堆中(stack),還有傳回值等等。用完了,作業系統就會回收這部分記憶體空間。對於C程式員而言,可以自行從棧中(heap)申請記憶體空間,用完了,也需要自己手動釋放。
作為PHP程式言而言,我們關心的是全域變數、靜態變數、局部變數、函數參數以及函數傳回值。局部變數和函數參數基本上一樣,在初始化的時候分配記憶體空間,退出函數後作業系統會回收記憶體空間。而全域變數與靜態變數要直php指令碼運行結束後,記憶體空間才會被釋放。與全域變數不同的時,所有靜態變數在程式執行之前就初始化並且分配了記憶體空間。
注:
1.函數外部聲明靜態變數意義不大,函數內部聲明靜態變數受限於範圍,函數外部不能修改函數內部靜態變數。
2.引用變數,也是變數,只不過它的值是變數的記憶體位址。
php保留字 global和static
| 代碼如下 |
複製代碼 |
<?php $i = $j = 8; function global_var() { global $j, $b; $c = $j = $b = $i = 4; } global_var(); echo "i:$i, j:$j b:$b c:$c n"; //i:8, j:4 b:4 c: ?>
|
函數外和內都有變數$i,但是他們二個是完全不同的變數。函數外的$i是全域變數,該記憶體空間直到指令碼運行結束後才會被釋放。函數內的$i是局部變數,程式流經過函數的時候,初始化,退出函數的時候,記憶體被系統回收,再次調用函數,則再次分配記憶體空間和回收記憶體空間。二次分配的記憶體空間有可能是同一記憶體位址,也有可能不能同一記憶體位址。
與$i不同的是$j,通過關鍵字global將局部變數”轉為”全域變數。當調用函數global_var()的時候,並不會重新給$j分配記憶體空間。同樣的,可以在函數外列印$b,卻不能列印$c是因為$b是全域變數,不會被銷毀。而$c則不能列印,$c已經不存在了,在退出函數就給銷毀了。
| 代碼如下 |
複製代碼 |
<?php $a = 2; static $b = 2; static $c = 3; function global_var() { static $i, $c; global $j, $a; $c = $a = $b = $i = $j = 4; } global_var(); echo "a:$a b:$b c:$c i:$i j:$j"; //a:4 b:2 c:3 i: j:4 ?>
|
首先,我們看函數外的$b和$c,即是全域變數又是static變數。這裡static修飾沒有太大的意義,因為他們都存放在資料區段(data-segment),直到指令碼運行完了之後才會被回收。然後,我們再看函數裡面的$i和$c,函數調用後,$i和$c其實都沒有被回收,但是$i輸出是NULL和$c輸出是3,這是因為他們的範圍是函數內部,不是函數外部,也就是說$i和$c在函數外是不可見的。函數內static變數的意義就在於此:僅函數內部可見且不會被銷毀。也就是說,保證函退出函數,變數也不會被回收,但又不會被其它函數修改。(註:函數外和函數內的$c是二個不同的變數)
| 代碼如下 |
複製代碼 |
<?php function global_var() { static $i; ++$j; ++$i; echo "j:$j i:$i n"; } global_var(); //j:1 i:1 global_var(); //j:1 i:2 global_var(); //j:1 i:3 ?>
|
上例中,變數$j一直都是1,而$i每調用一次就累加1。這是因為,局部變數存放在堆段,每次退出函數時都會被回收。而$i存放在存放在資料區段(data-segment),直到程式執行完畢才會被回收。我們平常說的static變數,如果沒有特別指明,都說的是函數內部的static變數。
引用函數與static變數
既然static變數要直到指令碼執行結束,才會被銷毀。那麼,有沒有辦法訪問該變數的值呢?我們來看看下面的樣本:
| 代碼如下 |
複製代碼 |
<?php get_local_static_var(); $ptr = &get_local_static_var(); get_local_static_var(); ++$ptr; get_local_static_var(); what_i($ptr); get_local_static_var(); //?? what_p($ptr); get_local_static_var(); //?? function &get_local_static_var() { static $i; ++$i; echo "i:$i n"; return $i; } function what_i($ptr) { $i = &get_local_static_var(); ++$i; ++$ptr; } function what_p(&$ptr) { $i = &get_local_static_var(); ++$i; ++$ptr; } ?>
|
二個凝問號處,分別輸出是8和12。這就說明了只要變數沒有被銷毀,還是可以被訪問。我們可以通過引用函數將static變數的地址返回其它函數。其它函數則可通過static變數的地址訪問並且修改它的值。
上例第一處??,為什麼是8,而不是9。這是因為what_i($ptr)函數,要求參數是按值傳遞,即此處的$ptr實參值是5,且參數$ptr和全域變數$ptr是二個不同的變數。第二處??的值是12,為什麼不是11的道理亦是如此。what_p(&$ptr)函數,要求參數是按引用傳遞,即此處的$ptr是指向static變數$i的地址,需要注意的是參數$ptr和全域變數$ptr也是二個不同的變數,只不過他們都指向同一個地方。
drupal應用賞析
drupal定義了一個drupal_static函數,其它函數的static變數都存放在一個數組中,然後對drupal應用到的所有static進行統一管理,比如賦值,重設,刪除等。我覺得,這是一個好辦法。
| 代碼如下 |
複製代碼 |
<? function &drupal_static($name, $default_value = NULL, $reset = FALSE) { static $data = array(), $default = array(); if (!isset($name)) { foreach ($default as $name => $value) { $data[$name] = $value; } return $data; } if ($reset) { if (array_key_exists($name, $default)) { $data[$name] = $default[$name]; } else { return $data; } } elseif (!array_key_exists($name, $data)) { $default[$name] = $data[$name] = $default_value; } return $data[$name]; } function ip_address() { $ip_address = &drupal_static(__FUNCTION__); if (!isset($ip_address)) { $ip_address = $_SERVER['REMOTE_ADDR']; if (variable_get('reverse_proxy', 0)) { if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { $reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array()); if (!empty($reverse_proxy_addresses) && in_array($ip_address, $reverse_proxy_addresses, TRUE) ) { $ip_address_parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $ip_address = trim(array_pop($ip_address_parts)); } } if (array_key_exists('HTTP_X_CLUSTER_CLIENT_IP', $_SERVER)) { $ip_address = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP']; } } } return $ip_address; } ip_address(); //在drupal中很多這樣的應用方式,將其它函數的static變數都存放到一個地方,即drupal_static的data中,然後再統一管理,比如重設等等。 ?> |