免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2255 | 回复: 1
打印 上一主题 下一主题

php中非静态方法的静态调用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-11-08 17:24 |只看该作者 |倒序浏览
本帖最后由 听老歌 于 2011-11-08 17:25 编辑

php中非静态方法的静态调用

参考资料:
1 Static method vs Non Static method  
http://bytes.com/topic/php/answe ... s-non-static-method

2 PHP static method performance
http://vega.rd.no/articles/php-static-method-performance


php是个很诡异的语言。当然,这是对学习过C++或者Java等面向对象语言的人来说。
php 可以定义静态的方法,然后通过className::staticMethod()形式来调用。非静态的方法,当然通过 classObject->nonStaticMethod()使用。这个其他语言中也是如此,没什么大惊小怪的。可是,您能用 className::nonStaticMethod()调用非静态方法吗?这方面恐怕Java和C++要冷汗直流了。其实,php自己也是满脸黑线。为什么这么说呢?
先来看看面向对象的静态和非静态。面向对象的语言中,都会支持静态方法。静态方法,属于类的固定资产的;非静态的方法,属于类的实例的私有财产。在内存中,静态方法,对于整个类也就只存了这么一份;无论你new了多少个实例对象,它们共用的也就这么一份。对于非静态的就不一样了,你new几个,内存就给你new几份。另外,静态方法内不可以调用非静态方法,非静态方法内却可以调用静态方法。这个就是静态和非静态的区别。
面向对象用static关键字来定义静态。未被标明是静态的方法,是不可以用类名加两个冒号的形式调用的。php和其它很有区别的一点就是这个了:php中未被标明是静态的方法,也可以用类名加两个冒号的形式调用。那么为什么php有这种语法?又为什么感到很无奈呢?
-----以下说明php无奈的故事据相关资料改编,已经过演义处理--------
php 之所以发展如此迅速,得益于它的速度。作为脚本语言,php追求高速度和简洁方便,所以选择了解释执行和使用过程方法。后来为了与国际接轨,引入了面向对象的概念。而就是在引入这个面向对象的特征时,发生了一件令php目瞪口呆,最终无可奈何的事情。面向对象有个很重要的概念就是继承。在继承中,子类如果覆盖父类的方法,同时需要调用父类的同名方法,该怎么办呢?php4版本提供了这样一种方法:parentClassName::method()。提出此种方法之时,有识之士已经发现了问题:这个调用方式,不正是静态方法的调用方式吗?php4随即答曰:不碍事。类中使用时,可以判断此方式为子类正在调用父类方法;非类中使用时,就判断为静态调用了。所需要的只是发现此种调用时查询一下方法映射就好了。其实,一想,也确实是那么回事。php4后来想想,如果每次调用都检验一下此次调用是否合法,那多少也会影响性能,不如这个问题就交给程序员去控制吧:他们会知道只在类中使用此形式的调用的。唉,可惜天不遂人愿。php4低估了程序员们的创造力!程序员们很快发现了这个方式,并且不余遗力地使用起来。许多集成的API也开始使用这种怪癖的方式。php无奈了,随即在php5中引入了另一种方式,使用关键字parent来调用父类函数:parent::method()。但是,想要放弃php的非静态方法的静态调用,着实是不再可能了。
--------------------------------------------------------
不过,话说回来,这种php的怪癖方式,有什么好处吗?性能和内存占用方面如何呢?
于是我开始推理了:定义了一个非静态的方法,静态调用时,php首先转换此方法为静态定义,加载入静态内存区域,然后执行。通常一次业务,只使用一个业务处理类中的一个方法,如果使用非静态定义,静态调用,内存中岂不是只加载了这个业务类中的一个方法,不是就实现了静态方法的按需加载吗?岂不是要省下一部分内存?性能方面,无论是静态调用,还是对象调用,反正都是执行一个方法,性能还不是一样?并且静态调用非静态定义方法还省了一个new语句。嗯,嗯。这么想的同时,手就开始写上了。
那么实际如何呢?我做了一个小测试。

PHP code
  1. t
  2. ::
  3. start();t
  4. ::
  5. end
  6. ();
  7. //
复制代码
消除t类首次加载的影响
  1. t
  2. ::
  3. start();
  4. model_profile_base
  5. ::
  6. getBaseInfo(
  7. $uid
  8. );
  9. t
  10. ::
  11. end
  12. ();

  13. t
  14. ::
  15. start();

  16. $model

  17. =

  18. new
  19. model_profile_base();

  20. $model
  21. ->
  22. getBaseInfo(
  23. $uid
  24. );
  25. t
  26. ::
  27. end
  28. ();
复制代码
model_profile_base是处理基本资料的一个业务类,比较复杂,比较接近于项目中的业务处理实际。
下面是用到的计时和统计内存的t类的定义:
  1. PHP code



  2. <?
  3. php

  4. function
  5. microtime_float()
  6. {
  7.    
  8. list
  9. (
  10. $usec
  11. ,

  12. $sec
  13. )
  14. =

  15. explode
  16. (
  17. "

  18. "
  19. ,

  20. microtime
  21. ());
  22.    
  23. return
  24. ((
  25. float
  26. )
  27. $usec

  28. +
  29. (
  30. float
  31. )
  32. $sec
  33. );
  34. }

  35. class
  36. t{
  37.    
  38. static

  39. $start_time
  40. ;
  41.    
  42. static

  43. $end_time
  44. ;
  45.    
  46. static

  47. $start_memory
  48. ;
  49.    
  50. static

  51. $end_memory
  52. ;
  53.    
  54.    
  55. public

  56. static

  57. function
  58. start()
  59.     {
  60.         self
  61. ::
  62. $start_memory

  63. =
  64. memory_get_usage();
  65.         self
  66. ::
  67. $start_time

  68. =
  69. microtime_float();
  70.         
  71. echo

  72. '
  73. <br/>Start @
  74. '
  75. .
  76. self
  77. ::
  78. $start_time
  79. .
  80. '
  81. (
  82. '
  83. .
  84. self
  85. ::
  86. $start_memory
  87. .
  88. '
  89. )|------->
  90. '
  91. ;
  92.     }
  93.    
  94.    
  95. public

  96. static

  97. function

  98. end
  99. ()
  100.     {
  101.         self
  102. ::
  103. $end_time

  104. =
  105. microtime_float();
  106.         self
  107. ::
  108. $end_memory

  109. =
  110. memory_get_usage();
  111.         
  112. echo

  113. '
  114. End @
  115. '
  116. .
  117. self
  118. ::
  119. $end_time
  120. .
  121. '
  122. (
  123. '
  124. .
  125. self
  126. ::
  127. $end_memory
  128. .
  129. '
  130. ) :
  131. '
  132. ;
  133.         
  134. echo

  135. '
  136. |======= 共耗时:
  137. '
  138. .
  139. (self
  140. ::
  141. $end_time
  142. -
  143. self
  144. ::
  145. $start_time
  146. )
  147. .
  148. '
  149. ,共用内存:
  150. '
  151. .
  152. (self
  153. ::
  154. $end_memory
  155. -
  156. self
  157. ::
  158. $start_memory
  159. );
  160.     }
  161. }
复制代码
这样,只调用一次,结果如下:

  1. PHP code


  2. Start @
  3. 1287561987.1805
  4. (
  5. 1008368
  6. )
  7. |------->
  8. End
  9. @
  10. 1287561987.1806
  11. (
  12. 1008368
  13. )
  14. :|=======
  15. 共耗时:
  16. 3.2901763916016E-5
  17. ,共用内存:
  18. 0

  19. Start @
  20. 1287561987.1806
  21. (
  22. 1008368
  23. )
  24. |------->
  25. End
  26. @
  27. 1287561987.1938
  28. (
  29. 1586452
  30. )
  31. :|=======
  32. 共耗时:
  33. 0.013248920440674
  34. ,共用内存:
  35. 578084

  36. Start @
  37. 1287561987.1938
  38. (
  39. 1586452
  40. )
  41. |------->
  42. End
  43. @
  44. 1287561987.1945
  45. (
  46. 1586652
  47. )
  48. :|=======
  49. 共耗时:
  50. 0.00065183639526367
  51. ,共用内存:
  52. 200
复制代码
第二行是静态调用非静态方法,第三行是正常调用非静态方法。然后,我发现我的推理悲剧了。刷了好几次页面,统计结果在数量级上都差不多。静态调用非静态方法无论内存占用还是性能上都不敢恭维。这样的结果有点令人咂舌。
那么,再试一下循环执行多次的结果:

PHP code
  1. t
  2. ::
  3. start();t
  4. ::
  5. end
  6. ();
  7. //
  8. 消除t类首次加载的影响


  9. t
  10. ::
  11. start();

  12. for
  13. (
  14. $i
  15. =
  16. 0
  17. ;
  18. $i
  19. <
  20. 1000
  21. ;
  22. ++
  23. $i
  24. ) model_profile_base
  25. ::
  26. getBaseInfo(
  27. $uid
  28. );
  29. t
  30. ::
  31. end
  32. ();

  33. t
  34. ::
  35. start();

  36. $model

  37. =

  38. new
  39. model_profile_base();

  40. for
  41. (
  42. $i
  43. =
  44. 0
  45. ;
  46. $i
  47. <
  48. 1000
  49. ;
  50. ++
  51. $i
  52. )
  53. $model
  54. ->
  55. getBaseInfo(
  56. $uid
  57. );
  58. t
  59. ::
  60. end
  61. ();
复制代码
于是更让人无语的结果出来了:
  1. PHP code


  2. Start @
  3. 1287562243.5799
  4. (
  5. 1009372
  6. )
  7. |------->
  8. End
  9. @
  10. 1287562243.5799
  11. (
  12. 1009372
  13. )
  14. :|=======
  15. 共耗时:
  16. 3.0040740966797E-5
  17. ,共用内存:
  18. 0

  19. Start @
  20. 1287562243.58
  21. (
  22. 1009372
  23. )
  24. |------->
  25. End
  26. @
  27. 1287562244.1532
  28. (
  29. 1587544
  30. )
  31. :|=======
  32. 共耗时:
  33. 0.57321000099182
  34. ,共用内存:
  35. 578172

  36. Start @
  37. 1287562244.1532
  38. (
  39. 1587544
  40. )
  41. |------->
  42. End
  43. @
  44. 1287562244.6921
  45. (
  46. 1587744
  47. )
  48. :|=======
  49. 共耗时:
  50. 0.53887605667114
  51. ,共用内存:
  52. 200
复制代码
除了两种方式时间上开始接近外(并且还是正常调用比较利索),内存上仍然有天壤之别。失望之余,查了下网上,发现也有人做了类似的测试。我就直接把结果拷上来吧:
(可能光看结果,会感觉有点难于理解,可以在这里找到详细说明:http://vega.rd.no/articles/php-static-method-performance)

测试结果 (ORDER BY time DESC):

PHP code



============
  1. Which method
  2. ========================
  3. Time
  4. ======

  5. Inline calculation                             
  6. 0.0805
  7. s
  8. Normal
  9. function
  10. call                           
  11. 0.3438
  12. s
  13. Normal method called through
  14. object
  15.             
  16. 0.4118
  17. s

  18. Static
  19. method called statically               
  20. 0.4280
  21. s
  22. Unspecified method called through
  23. object
  24. ()     
  25. 0.4294
  26. s
  27. Unspecified method called statically()         
  28. 0.6960
  29. s
复制代码
如此看来,静态调用非静态方法在性能和内存上都不占优势;另外,此种调用方法容易产生维护混乱。那么,来个短而有力的总结:静态调用非静态方法不可取。[code=PHP][/code][code=PHP][/code]

论坛徽章:
0
2 [报告]
发表于 2011-11-14 10:16 |只看该作者
谢谢楼主分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP