`
wangshaofei
  • 浏览: 283503 次
  • 性别: 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]

分享到:
评论

相关推荐

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

    这意味着在调用静态方法时,不需要先创建类的对象。静态方法通常用于执行与类相关的操作,但不涉及特定对象的状态。 **2. 实例方法** 实例方法也称为非静态方法,它依赖于类的一个特定实例。实例方法能够访问类中...

    静态方法和非静态方法的调用.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) ...

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

    以下是使用jQuery .load()方法调用PHP文件的几种方式: 1. 加载一个不含传递参数的PHP文件: ```javascript $("#myID").load("test.php"); ``` 2. 加载一个含有一个传递参数的PHP文件: ```javascript $("#myID")....

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

    调用静态属性和方法的语法是`类名::属性名`或`类名::方法名()`。如: ```php echo Math::$pi; Math::Max(5, 10); ``` 在PHP中,静态属性和方法是在类第一次被加载或调用时创建的,这与Java等其他语言的类加载机制...

    (js)静态与非静态方法

    3. **便捷性**:可以直接通过类名调用静态方法,无需实例化对象,使得调用更加方便。 #### 实现方式 ```javascript function Service() {} // 静态方法 Service.showAllService = function () { $.getJSON(...

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

    在上述提供的内容中,给出了两个示例,展示了如何在PHP中使用`self`和`$this`关键字来调用静态方法和非静态方法。这两个关键字在类内部的上下文中用于引用当前类及其成员。 第一个示例演示了在非静态方法中调用静态...

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

    当静态方法调用非静态方法时,如果非静态方法内部使用 `$this`,那么PHP会使用调用静态方法时的 calling scope,即调用静态方法的类实例。 例如,如果我们在上述例子中添加一个静态构造方法: ```php class A { ...

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

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

    // 不创建对象调用静态方法 HasStaticMethod oa = new HasStaticMethod(); oa.callMe(); // 使用对象调用静态方法 } } ``` 这段代码演示了如何在不创建对象的情况下调用静态方法,这在Java中是允许的,因为静态...

    通过反射调用静态方法

    本文将详细讲解如何通过反射调用静态方法,并探讨在特定场景下,如MyBatis中的应用。 首先,理解反射的概念是至关重要的。在Java中,反射API(java.lang.reflect)允许我们获取类的信息,包括类名、构造函数、方法...

    Java中静态方法和非静态方法的区别.docx

    静态方法的内存是固定在内存中的,因此,我们不需要使用定义了静态方法的类的对象来调用静态方法。要调用该方法,我们需要编写类名,后跟方法名语法。非静态方法的内存并不固定在 RAM 中,所以我们需要一个类对象来...

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

    由于静态成员的创建和调用不依赖于任何实例,因此在静态方法内部不存在对非静态成员的直接引用。 2. 内存使用:静态属性在内存中只有一份,由所有类的实例共享。这意味着对静态属性的任何修改,都会影响到所有实例...

    静态方法同步 与 非静态方法同步

    这意味着所有实例共享同一个锁,不论创建了多少个对象,所有线程在调用静态同步方法时都会争夺这个单一的锁。这样的同步机制适用于需要全局保护的资源或状态。 例如,在`SynchronizedTest.java`中可能会有以下静态...

    php面对对象中static静态属性和静态方法的调用_.docx

    然而,静态方法可以调用静态属性,使用 `self` 关键词来引用,如 `self::$name`。此外,静态方法也可以调用非静态方法,只要不使用 `$this`,而是通过类名或对象实例来调用,如 `self::say()` 或 `$p1-&gt;say()`。 在...

    浅析php静态方法与非静态方法的用法区分_.docx

    静态方法的特点在于它们与类关联,而非与类的实例关联,这意味着你可以直接通过类名来调用静态方法,而无需先创建类的对象。这在处理一些全局性的任务或不需要访问实例成员的情况下非常有用。 静态方法使用`static`...

    MFC DLL动态调用及静态调用

    静态调用MFC DLL意味着在编译时将MFC库与DLL一起链接,使得主程序不需要在运行时加载DLL。这通常用于减少运行时依赖,但会增加可执行文件大小。 1. 创建MFC DLL项目:与动态调用相同,但在项目设置中选择“Use MFC ...

    LINUX C调用JAVA的静态方法和非静态方法(实例方法)小实例

    在Linux环境中,C语言可以通过Java Native Interface (JNI) 来调用Java的静态和非静态方法,实现两者之间的交互。JNI是Java平台标准的一部分,它允许Java代码和其他语言写的代码进行交互,使得C/C++程序员可以编写...

    DynamicCustomVI_动态调用_labview_静态调用_

    - **适应性**:动态调用更适用于需要根据条件或输入动态选择不同功能的场合,而静态调用则更适合于已知调用链路且不需频繁变化的情况。 - **维护**:静态调用的代码结构清晰,易于维护;但动态调用的代码可能需要...

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

    - **静态方法**:通常在效率上优于非静态方法,因为它们不需要为每次调用创建新的实例。然而,静态方法不会自动销毁,可能会导致内存泄漏问题。 - **非静态方法**:通过实例调用,允许更灵活地管理内存资源,但每次...

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

    - 通过加载的 DLL 实例调用静态方法并传递参数。 2. **Python 调用 C# 非静态方法** - 非静态方法需要先创建 C# 类的实例,然后通过实例调用方法。在 Python 中,这通常意味着需要使用 `ctypes` 创建结构体来表示...

Global site tag (gtag.js) - Google Analytics