在PHP里,object方法与class方法的探讨

  先统一名词解释:何谓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);拿到循环外面后再运行程序。

你可能感兴趣的:(PHP)