在PHP中,靜態變數的解釋是存在於類範圍的變數,在第一次初始化時給變數賦值,以後類初始化時,靜態變數將不會再被重新賦值,主要用於一個類具有多個執行個體時的變數共用,以下為PHP的靜態變數使用代碼:
使用靜態變數
變數範圍的另一個重要特性是靜態變數(static variable)。靜態變數僅在局部函數域中存在,但當程式執行離開此範圍時,其值並不丟失。看看下面的例子:
例子 7-4. 示範需要靜態變數的例子
| 代碼如下 |
複製代碼 |
<?php function Test () { $a = 0; echo $a; $a++; } ?>
|
本函數沒什麼用處,因為每次調用時都會將 $a 的值設為 0 並輸出 "0"。將變數加一的 $a++ 沒有作用,因為一旦退出本函數則變數 $a 就不存在了。要寫一個不會丟失本次計數值的計數函數,要將變數 $a 定義為靜態:
例子 7-5. 使用靜態變數的例子
| 代碼如下 |
複製代碼 |
<?php function Test() { static $a = 0; echo $a; $a++; } ?> |
現在,每次調用 Test() 函數都會輸出 $a 的值並加一。
靜態變數也提供了一種處理遞迴函式的方法。遞迴函式是一種調用自己的函數。寫遞迴函式時要小心,因為可能會無窮遞迴下去。必須確保有充分的方法來中止遞迴。一下這個簡單的函數遞迴計數到 10,使用靜態變數 $count 來判斷何時停止:
例子 7-6. 靜態變數與遞迴函式
| 代碼如下 |
複製代碼 |
<?php function Test() { static $count = 0; $count++; echo $count; if ($count < 10) { Test (); } $count--; } ?> |
注: 靜態變數可以按照上面的例子聲明。如果在聲明中用運算式的結果對其賦值會導致解析錯誤。
例子 7-7. 聲明靜態變數
| 代碼如下 |
複製代碼 |
<?php function foo(){ static $int = 0; // correct static $int = 1+2; // wrong (as it is an expression) static $int = sqrt(121); // wrong (as it is an expression too) $int++; echo $int; } ?> |
靜態方法
| 代碼如下 |
複製代碼 |
<?php class Fruit { public static $category = "I'm fruit"; static function find($class) { $vars = get_class_vars($class) ; echo $vars['category'] ; } } class Apple extends Fruit { public static $category = "I'm Apple"; } Apple::find("Apple"); ?> 程式運行結果: 1 I'm Apple |
Program List:重寫基類方法
在衍生類別重寫基類的方法。
| 代碼如下 |
複製代碼 |
<?php class Fruit { static function Foo ( $class = __CLASS__ ) { call_user_func(array($class, 'Color')); } } class Apple extends Fruit { static function Foo ( $class = __CLASS__ ) { parent::Foo($class); } static function Color() { echo "Apple's color is red"; } } Apple::Foo(); // This time it works. ?> 程式運行結果:
Apple's color is red |
Program List:靜態數組的使用
靜態和const範圍都可以用::操作符訪問,如果你想使用::操作符訪問數組,你需要事先將數組聲明為靜態
| 代碼如下 |
複製代碼 |
<?php class Fruit { static $color = array('color1' => 'red', 'color2' => 'yellow'); } class Apple { public function __construct() { var_dump(Fruit::$color); } } class Banana { public function __construct() { Fruit::$color = FALSE; } } new Apple(); // prints array(2) { ["color1"]=> string(3) "red" ["color2"]=> string(6) "yellow" } echo '<br />'; new Banana(); new Apple(); // prints bool(false) ?> |
Program List:再來一個單例模式
Static真的很酷,下面的程式示範了如何獲得一個已經存在的執行個體。
| 代碼如下 |
複製代碼 |
<?php class Singleton { private static $instance=null; private $value=null; private function __construct($value) { $this->value = $value; } public static function getInstance() { if ( self::$instance == null ) { echo "<br>new<br>"; self::$instance = new Singleton("values"); } else { echo "<br>old<br>"; } return self::$instance; } } $x = Singleton::getInstance(); var_dump($x); // returns the new object $y = Singleton::getInstance(); var_dump($y); // returns the existing object ?> |
例
靜態變數與靜態方法
| 代碼如下 |
複製代碼 |
class A { static $i = 10; public function set($n) { self::$i = $n; } public function get() { return self::$i; } } $a = new A(); $a->set(11); $a1= new A(); echo $a1->get(); |
輸出結果為11,可以看到類A在第二次執行個體化後,靜態變數$i依然與上一次執行個體化時後設定的$i值是一致的。用java來解釋,其實就是一個類的靜態變數在多個執行個體中都使用了一個記憶體空間,我覺得這樣解釋更加便於理解。因為靜態變數和靜態方法不需要執行個體化就可以使用,因而在檔案被載入後靜態變數就會初始化,而靜態方法則會被註冊。這也就可以理解,為什麼java類的入口會這樣的了:
| 代碼如下 |
複製代碼 |
public static void main(String[] args) { } |
我以前一直覺得由於靜態方法不需要執行個體化就可以直接使用,節約了執行個體化的巨大開銷,因而在使用一個類的方法時我更加傾向於直接靜態調用而避免執行個體化。對於這個問題,我與同事已經爭論過很多次,他不主張靜態調用主要有以下想法:
1.執行個體化類更加符合物件導向編程的思想;
2.靜態調用方法並不能在消耗上有較大的節約。
對於這個問題,我還是堅持自己的觀點,但也並不是無論什麼時候都使用靜態調用。我主要有以下想法:
1.由於靜態變數在檔案被載入時就會被初始化,因此如果有多個類,並且類中存在多個靜態變數與方法,勢必在還未執行個體化時已消耗較多的記憶體(未驗證)。所以對於訪問不頻繁或特殊需要,不建議將一個方法設為static;
2.對於調用較為頻繁的類,我強烈建設使用static靜態和靜態方法,不僅可以共用記憶體空間,還可以共用資料。細心就會發現目前主流的PHP架構的基類都是使用的靜態調用方法。