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

WBOY
Release: 2016-06-13 12:33:40
Original
940 people have browsed it

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
<p>
<span style="color: #000000;">
t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">(); </span>
<span style="color: #008000;">//</span>
<span style="color: #008000;">消除t类首次加载的影响</span>
<span style="color: #008000;">
</span>
<span style="color: #000000;">t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();
model_profile_base</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">getBaseInfo(</span>
<span style="color: #800080;">$uid</span>
<span style="color: #000000;">);
t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">();

t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();
</span>
<span style="color: #800080;">$model</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">new</span>
<span style="color: #000000;"> model_profile_base();
</span>
<span style="color: #800080;">$model</span>
<span style="color: #000000;">-></span>
<span style="color: #000000;">getBaseInfo(</span>
<span style="color: #800080;">$uid</span>
<span style="color: #000000;">);
t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">();
</span>
</p>

Copy after login


model_profile_base是处理基本资料的一个业务类,比较复杂,比较接近于项目中的业务处理实际。
下面是用到的计时和统计内存的t类的定义:

PHP code
<p>
<span style="color: #000000;">
</span>
<span style="color: #000000;"></span>
<span style="color: #000000;">php
</span>
<span style="color: #0000ff;">function</span>
<span style="color: #000000;"> microtime_float()
{
   </span>
<span style="color: #0000ff;">list</span>
<span style="color: #000000;">(</span>
<span style="color: #800080;">$usec</span>
<span style="color: #000000;">,</span>
<span style="color: #000000;"> </span>
<span style="color: #800080;">$sec</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> </span>
<span style="color: #008080;">explode</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">"</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">"</span>
<span style="color: #000000;">,</span>
<span style="color: #000000;"> </span>
<span style="color: #008080;">microtime</span>
<span style="color: #000000;">());
   </span>
<span style="color: #0000ff;">return</span>
<span style="color: #000000;"> ((</span>
<span style="color: #0000ff;">float</span>
<span style="color: #000000;">)</span>
<span style="color: #800080;">$usec</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">+</span>
<span style="color: #000000;"> (</span>
<span style="color: #0000ff;">float</span>
<span style="color: #000000;">)</span>
<span style="color: #800080;">$sec</span>
<span style="color: #000000;">);
}
</span>
<span style="color: #0000ff;">class</span>
<span style="color: #000000;"> t{
    </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #800080;">$start_time</span>
<span style="color: #000000;">;
    </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #800080;">$end_time</span>
<span style="color: #000000;">;
    </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #800080;">$start_memory</span>
<span style="color: #000000;">;
    </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #800080;">$end_memory</span>
<span style="color: #000000;">;
    
    </span>
<span style="color: #0000ff;">public</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">function</span>
<span style="color: #000000;"> start()
    {
        self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_memory</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> memory_get_usage();
        self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_time</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> microtime_float();
        </span>
<span style="color: #0000ff;">echo</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">'</span>
<span style="color: #000000;"><br>Start @</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_time</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_memory</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">)|-------></span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">;
    }
    
    </span>
<span style="color: #0000ff;">public</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">static</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">function</span>
<span style="color: #000000;"> </span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">()
    {
        self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_time</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> microtime_float();
        self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_memory</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> memory_get_usage();
        </span>
<span style="color: #0000ff;">echo</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">End @</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_time</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_memory</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">) :</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">;
        </span>
<span style="color: #0000ff;">echo</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">|======= 共耗时:</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">(self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_time</span>
<span style="color: #000000;">-</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_time</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">'</span>
<span style="color: #000000;">.</span>
<span style="color: #000000;">(self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$end_memory</span>
<span style="color: #000000;">-</span>
<span style="color: #000000;">self</span>
<span style="color: #000000;">::</span>
<span style="color: #800080;">$start_memory</span>
<span style="color: #000000;">);
    }
}
</span>
</p>

Copy after login


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

PHP code
<p>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287561987.1805</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1008368</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287561987.1806</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1008368</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">3.2901763916016E-5</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287561987.1806</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1008368</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287561987.1938</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1586452</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">0.013248920440674</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">578084</span>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287561987.1938</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1586452</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287561987.1945</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1586652</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">0.00065183639526367</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">200</span>
<span style="color: #000000;"> 
</span>
</p>

Copy after login


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

PHP code
<p>
<span style="color: #000000;">
t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">(); </span>
<span style="color: #008000;">//</span>
<span style="color: #008000;">消除t类首次加载的影响</span>
<span style="color: #008000;">
</span>
<span style="color: #000000;">t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();
</span>
<span style="color: #0000ff;">for</span>
<span style="color: #000000;">(</span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">; </span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">
<span style="color: #000000;">1000</span>
<span style="color: #000000;">;</span>
<span style="color: #000000;">++</span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">) model_profile_base</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">getBaseInfo(</span>
<span style="color: #800080;">$uid</span>
<span style="color: #000000;">);
t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">();

t</span>
<span style="color: #000000;">::</span>
<span style="color: #000000;">start();
</span>
<span style="color: #800080;">$model</span>
<span style="color: #000000;"> </span>
<span style="color: #000000;">=</span>
<span style="color: #000000;"> </span>
<span style="color: #0000ff;">new</span>
<span style="color: #000000;"> model_profile_base();
</span>
<span style="color: #0000ff;">for</span>
<span style="color: #000000;">(</span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">=</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">; </span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">
<span style="color: #000000;">1000</span>
<span style="color: #000000;">;</span>
<span style="color: #000000;">++</span>
<span style="color: #800080;">$i</span>
<span style="color: #000000;">) </span>
<span style="color: #800080;">$model</span>
<span style="color: #000000;">-></span>
<span style="color: #000000;">getBaseInfo(</span>
<span style="color: #800080;">$uid</span>
<span style="color: #000000;">);
t</span>
<span style="color: #000000;">::</span>
<span style="color: #008080;">end</span>
<span style="color: #000000;">();
</span>
</span></span></p>

Copy after login



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

PHP code
<p>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287562243.5799</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1009372</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287562243.5799</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1009372</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">3.0040740966797E-5</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">0</span>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287562243.58</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1009372</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287562244.1532</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1587544</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">0.57321000099182</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">578172</span>
<span style="color: #000000;">
Start @</span>
<span style="color: #000000;">1287562244.1532</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1587544</span>
<span style="color: #000000;">)</span>
<span style="color: #000000;">|-------></span>
<span style="color: #008080;">End</span>
<span style="color: #000000;"> @</span>
<span style="color: #000000;">1287562244.6921</span>
<span style="color: #000000;">(</span>
<span style="color: #000000;">1587744</span>
<span style="color: #000000;">) </span>
<span style="color: #000000;">:|=======</span>
<span style="color: #000000;"> 共耗时:</span>
<span style="color: #000000;">0.53887605667114</span>
<span style="color: #000000;">,共用内存:</span>
<span style="color: #000000;">200</span>
<span style="color: #000000;"> 
</span>
</p>

Copy after login


除了两种方式时间上开始接近外(并且还是正常调用比较利索),内存上仍然有天壤之别。失望之余,查了下网上,发现也有人做了类似的测试。我就直接把结果拷上来吧:
(可能光看结果,会感觉有点难于理解,可以在这里找到详细说明:http://vega.rd.no/articles/php-static-method-performance)

测试结果 (ORDER BY time DESC):

PHP code
<p>
<span style="color: #000000;">
</span>
<span style="color: #000000;">============</span>
<span style="color: #000000;">Which method</span>
<span style="color: #000000;">========================</span>
<span style="color: #008080;">Time</span>
<span style="color: #000000;">======</span>
<span style="color: #000000;">
Inline calculation                             </span>
<span style="color: #000000;">0.0805</span>
<span style="color: #000000;"> s
Normal </span>
<span style="color: #0000ff;">function</span>
<span style="color: #000000;"> call                           </span>
<span style="color: #000000;">0.3438</span>
<span style="color: #000000;"> s
Normal method called through </span>
<span style="color: #0000ff;">object</span>
<span style="color: #000000;">            </span>
<span style="color: #000000;">0.4118</span>
<span style="color: #000000;"> s
</span>
<span style="color: #0000ff;">Static</span>
<span style="color: #000000;"> method called statically                </span>
<span style="color: #000000;">0.4280</span>
<span style="color: #000000;"> s
Unspecified method called through </span>
<span style="color: #0000ff;">object</span>
<span style="color: #000000;">()     </span>
<span style="color: #000000;">0.4294</span>
<span style="color: #000000;"> s
Unspecified method called statically()         </span>
<span style="color: #000000;">0.6960</span>
<span style="color: #000000;"> s
</span>
</p>

Copy after login


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

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!