`
wangshaofei
  • 浏览: 271062 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

php静态方法调用非静态方法不可取

    博客分类:
  • php
阅读更多

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

---------------------------------------------------------------------------------
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]

分享到:
评论

相关推荐

    静态方法和非静态方法的调用.pdf

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) ...

    C#静态方法与非静态方法的比较

    C#静态方法与非静态方法的比较

    Springboot Thymeleaf模板文件调用Java类静态方法

    方法名(参数)}”这种格式来调用Java类的静态方法。 开发环境:IntelliJ IDEA 2019.2.2 Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目。 1、pom.xml 加入Thymeleaf依赖 &lt;groupId&gt;org.spring...

    html静态页面调用php文件的方法

    主要介绍了html静态页面调用php文件的方法,在进行应用程序开发过程中非常具有实用价值,需要的朋友可以参考下

    PHP静态调用非静态方法的应用分析

    静态调用非静态方法!!这在java,c#中是不可想象的,也是绝对不行的。这样的错误在这些语言中会在编译阶段就被指出错误的。但是对于php这样的动态语言呢?首先这个是语法没有错误的,php –l 找不出错误来的。如果...

    PHP中静态方法(static)与非静态方法的使用及区别.docx

    PHP中静态方法(static)与非静态方法的使用及区别.docxPHP中静态方法(static)与非静态方法的使用及区别.docxPHP中静态方法(static)与非静态方法的使用及区别.docxPHP中静态方法(static)与非静态方法的使用及区别.docx

    (js)静态与非静态方法

    (js)静态与非静态方法,(js)静态与非静态方法

    浅谈PHP中静态方法和非静态方法的相互调用

    在PHP的非静态方法中可以调用静态方法 class test{ public static function strPrint(){ echo 'this is strPrint static function '; } public function staticFuncInvoke(){ self::strPrint(); } } $test...

    通过反射调用静态方法

    本例演示了如何使用反射,调用类的静态方法,封装了工具类ClsTool,统一实现静态方法的调用。使用反射,在特定场景下,能够很好的简化代码。例如mybatis

    Python 调用 C# 静态方法,非静态方法,传参

    Python 调用 C# 静态方法,非静态方法,传参 Python 调用C# 方法返回 DataSet Python 使用 Lambda 循环处理 DataSet.Tables

    c#静态方法和非静态方法详细介绍

    C#的类中可以包含两种方法:静态方法和非静态方法。 使用了static 修饰符的方法为静态方法,反之则是非静态方法。 静态方法是一种 特殊的成员方法,它不属于类的某一个具体的实例,而是属于类本身。所以对静态方法不...

    Java的静态方法调用.pdf

    Java的静态方法调用

    浅析php静态方法与非静态方法的用法区别

    下面小编就为大家带来一篇浅析php静态方法与非静态方法的用法区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    静态方法,静态成员变量的调用

    静态方法和实例方法的区别主要体现在两个方面: ...在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。

    webservice的动态调用和静态调用

    webservice的动态调用和静态调用。静态调用是指添加web引用的方式调用。动态调用是指通过反射等方式在代码中加载。

    浅析C#中静态方法和非静态方法的区别

    非静态在内存的存储上是离散的,因此静态方法和非静态方法,在调用速度上,静态方法速度一定会快点,因为非静态方法需要实例化,分配内存,但静态方法不用,但是这种速度上差异可以忽略不计  何时用静态方法,何时...

    VC动态静态相互调用示例

    VC动态静态相互调用示例,比如静态发布MFC里包含调用DLL,静态库调用动态库

Global site tag (gtag.js) - Google Analytics