设为首页 收藏本站
查看: 826|回复: 0

[经验分享] php静态方法调用非静态方法不可取

[复制链接]

尚未签到

发表于 2017-4-7 07:45:45 | 显示全部楼层 |阅读模式
  那天对这个主题比较感兴趣,于是就查了相关资料来记叙一下。不过,不知道自己写的到底有没有疏漏,所以,发到这里来给大家当靶子。如果您发现有什么叙述不正确的或不合理的,尽情拍砖——当然接受西红柿和鸡蛋。真理,只存在于辩论中。


---------------------------------------------------------------------------------

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


参考资料:

1 Static method vs Non Static method 

http://bytes.com/topic/php/answers/495206-static-method-vs-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



t

::
start();t
::
end
();
//
消除t类首次加载的影响


t
::
start();
model_profile_base

::
getBaseInfo(
$uid
);
t

::
end
();
t

::
start();

$model

=

new
model_profile_base();

$model
->
getBaseInfo(
$uid
);
t

::
end
();




  

model_profile_base是处理基本资料的一个业务类,比较复杂,比较接近于项目中的业务处理实际。

下面是用到的计时和统计内存的t类的定义:

PHP code




<?
php

function
microtime_float()
{

list
(
$usec
,

$sec
)
=

explode
(
"

"
,

microtime
());

return
((
float
)
$usec

+
(
float
)
$sec
);
}

class
t{

static

$start_time
;

static

$end_time
;

static

$start_memory
;

static

$end_memory
;

public

static

function
start()
{
self

::
$start_memory

=
memory_get_usage();
self

::
$start_time

=
microtime_float();

echo

'
<br/>Start @
'
.
self
::
$start_time
.
'
(
'
.
self
::
$start_memory
.
'
)|------->
'
;
}

public

static

function

end
()
{
self

::
$end_time

=
microtime_float();
self

::
$end_memory

=
memory_get_usage();

echo

'
End @
'
.
self
::
$end_time
.
'
(
'
.
self
::
$end_memory
.
'
) :
'
;

echo

'
|======= 共耗时:
'
.
(self
::
$end_time
-
self
::
$start_time
)
.
'
,共用内存:
'
.
(self
::
$end_memory
-
self
::
$start_memory
);
}
}




  

这样,只调用一次,结果如下:

PHP code



Start @

1287561987.1805
(
1008368
)
|------->
End
@
1287561987.1806
(
1008368
)
:|=======
共耗时:
3.2901763916016E-5
,共用内存:
0

Start @

1287561987.1806
(
1008368
)
|------->
End
@
1287561987.1938
(
1586452
)
:|=======
共耗时:
0.013248920440674
,共用内存:
578084

Start @

1287561987.1938
(
1586452
)
|------->
End
@
1287561987.1945
(
1586652
)
:|=======
共耗时:
0.00065183639526367
,共用内存:
200





  

第二行是静态调用非静态方法,第三行是正常调用非静态方法。然后,我发现我的推理悲剧了。刷了好几次页面,统计结果在数量级上都差不多。静态调用非静态方法无论内存占用还是性能上都不敢恭维。这样的结果有点令人咂舌。

那么,再试一下循环执行多次的结果:

PHP code



t

::
start();t
::
end
();
//
消除t类首次加载的影响


t
::
start();

for
(
$i
=
0
;
$i
<
1000
;
++
$i
) model_profile_base
::
getBaseInfo(
$uid
);
t

::
end
();
t

::
start();

$model

=

new
model_profile_base();

for
(
$i
=
0
;
$i
<
1000
;
++
$i
)
$model
->
getBaseInfo(
$uid
);
t

::
end
();




  


于是更让人无语的结果出来了:

PHP code



Start @

1287562243.5799
(
1009372
)
|------->
End
@
1287562243.5799
(
1009372
)
:|=======
共耗时:
3.0040740966797E-5
,共用内存:
0

Start @

1287562243.58
(
1009372
)
|------->
End
@
1287562244.1532
(
1587544
)
:|=======
共耗时:
0.57321000099182
,共用内存:
578172

Start @

1287562244.1532
(
1587544
)
|------->
End
@
1287562244.6921
(
1587744
)
:|=======
共耗时:
0.53887605667114
,共用内存:
200





  

除了两种方式时间上开始接近外(并且还是正常调用比较利索),内存上仍然有天壤之别。失望之余,查了下网上,发现也有人做了类似的测试。我就直接把结果拷上来吧:

(可能光看结果,会感觉有点难于理解,可以在这里找到详细说明:http://vega.rd.no/articles/php-static-method-performance)


测试结果 (ORDER BY time DESC):

PHP code




============
Which method
========================
Time
======

Inline calculation                             

0.0805
s
Normal

function
call                           
0.3438
s
Normal method called through

object
            
0.4118
s

Static
method called statically               
0.4280
s
Unspecified method called through

object
()     
0.4294
s
Unspecified method called statically()         

0.6960
s




  

如此看来,静态调用非静态方法在性能和内存上都不占优势;另外,此种调用方法容易产生维护混乱。那么,来个短而有力的总结:静态调用非静态方法不可取。[code=PHP][/code][code=PHP][/code]

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-361199-1-1.html 上篇帖子: PHP高级工程师具备的技能及素质 下篇帖子: 利用PHP扩展trie_filter做敏感词过滤
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表