在PHP里,object方法與class方法的探討

作者: 老王  來源: 老王的技術手冊  發布時間: 2010-12-05 17:51  閱讀: 2388 次  推薦: 1   原文鏈接   [收藏]  

  先統一名詞解釋:何謂object方法?何謂class方法?從下面例子代碼可以看出:

 
01 class Foo
02 {
03 public function a_object_method()
04 {
05 // ...
06 }
07
08 public static function a_class_method()
09 {
10 // ...
11 }
12 }

  object方法是動態的,先實例化對象然后再調用;class方法是靜態的,不用實例化對象,直接在類上調用。

  在PHP里,是object方法好?還是class方法好?乍一聽起來,問題本身似乎就有問題,因為object方法和class方法的意義原本就不同,不存在可比性,就好像討論empty和isset哪個快一樣,因為它們的意義不同,所以不管結果如何,都沒有太大意義。但是由于PHP運行環境的特殊性,讓我們不能再用老眼光看問題,下面詳細闡述一下:

  在類方法里只能使用類屬性,也就是static屬性,為了更深刻的理解問題,先看看Java中的static屬性:Java程序會運行在Tomcat之類的容器里,如果我們設置一個類的static屬性,只要你別重啟容器,那么變化就會被容器持久保存在內存中,不僅每次請求,而且每個對象都能共享它,再看看PHP,由于沒有所謂容器的概念,它的運行是瞬態的,在多次請求間,如果使用對象的話,它們需要重復的實例化出來,static屬性僅僅在當次請求有效,而不會持久保存在內存中,從這個意義上講,在PHP里,既然每次請求開始時都要重新建立運行環境,結束后一切都灰飛煙滅,那么可以把class本身也看做是對象,一種不用實例化的對象,我們姑且稱之為類對象,而static屬性就可以看做是類對象的屬性。那在PHP中什么時候可以使用這樣的類對象呢?主要看你是否需要區分狀態!比如說MVC中的Action,一般一次請求里僅僅會用一次,所以不需要區分狀態,所以就可以使用類對象的形式;再比如文章列表頁,如果每條記錄都是一個對象的話,那么就必須使用實例化出來的真正的對象,而不能使用類對象,因為在類對象里,只能使用static屬性,不能區分不同的狀態。

如此說來,假如我們設計一個PHP框架的話,由于在一次請求里,框架本身的組件基本都僅僅執行一次(比如說前端控制器),不需要區分狀態,所以除了可以使用object方法,還可以使用class方法。那么class方法是否可取就看是利大于弊,還是弊大于利。

  先看看利,我們用程序來測試一下性能:

 
01 <pre>
02 <?php
03
04 class Bench
05 {
06 private $object_bar;
07
08 private static $class_bar;
09
10 public function __construct($bar)
11 {
12 $this->object_bar = $bar;
13 }
14
15 public function a_object_method()
16 {
17 return $this->object_bar;
18 }
19
20 public static function init($bar)
21 {
22 self::$class_bar = $bar;
23 }
24
25 public static function a_class_method()
26 {
27 return self::$class_bar;
28 }
29 }
30
31
32 $counter = 100;
33
34 $start = microtime(true);
35 for ($i = 0; $i < $counter; $i++) {
36 $bench = new Bench(null);
37 $bench->a_object_method();
38 }
39 $end = microtime(true);
40
41 echo "Object Method: ", ($end - $start), "\n";
42
43 $start = microtime(true);
44 for ($i = 0; $i < $counter; $i++) {
45 Bench::init(null);
46 Bench::a_class_method();
47 }
48 $end = microtime(true);
49
50 echo "Class Method: ", ($end - $start), "\n";
51
52 ?>
53 </pre>

  每次請求,一般情況下都要設置一些初始化參數,所以在測試時我們加入了初始化的過程,結果顯示class方法比object方法稍微快一點點:

  Object Method: 0.00071191787719727
  Class Method:  0.00057101249694824

  注意:測試環境為 PHP5.3.2,Windows,Linux下結論類似,其它PHP版本未測試。

  再看看弊,其實你搜索一下static is evil就能看到很多:

  大量使用static之后,多態基本不可能了,繼而Mock也不可能了,可測試性打折扣。

  總結:在PHP里,到底應該如何OOP,我個人觀點總在搖擺,有時候覺得object方法好,有時候又覺得class方法好,但就目前來說,我覺得鑒于PHP特殊的運行方式,應該重視class方法,但不應該大范圍使用,相比較而言,更傾向于傳統的object方法,因為class方法雖然不用實例化對象,但從測試結果來看,和object方法相比,它提升的性能幅度非常有限,而作為代價,多態,可測試性等必要特性都統統喪失了,這讓我有種得不償失的感覺。

  補充:即便作為優勢,class方法比object方法快一點點,但這也不是絕對的。某些情況下,class方法慢于object方法:如果單個類/對象方法調用次數很多的話,那么由于單獨的對象操作符“->”快于類操作符“::”,若干個方法調用后,累加起來甚至能抵消實例化的 效率損耗,從而導致object方法快于class方法,如果想驗證,可以把上面測試代碼中的$bench = new Bench(null);和Bench::init(null);拿到循環外面后再運行程序。

1
1
 
標簽:PHP
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()