首頁 >後端開發 >php教程 >PHP常用魔術方法的效能探究

PHP常用魔術方法的效能探究

*文
*文原創
2017-12-23 10:08:271918瀏覽

效能往往是衡量程式碼很重要的一個標準。我們日常編碼中常會用到一些魔術方法,這些PHP提供的魔術方法是否會影響我們程式的表現呢?是否需要減少魔術方法 的使用?本文將透過測試對比來了解魔術方法對表現的影響。

疑惑

魔術方法真的表現比較差嗎?

PHP7裡使用魔術方法的表現還是有問題嗎?

我們應該如何合理的使用魔術方法?

方案

面對我的疑惑,我的方案是:

統計對比使用魔術方法和不使用魔術方法腳本執行的時間差異

PHP5.6.26-1 下連續執行腳本n次

統計執行時間的平均值/最小值/最大值

PHP7.0.12-2 下連續執行腳本n次

統計執行時間的平均值/最小值/最大值


測試

__construct


首先我們先來看看建構子__construct的實驗,php腳本如下:

<?php
/**
 * 魔术方法性能探索
 *
 * 构造函数
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
require(&#39;./function.php&#39;);
if (!isset($argv[1])) {
    die(&#39;error: variable is_use_magic is empty&#39;);
}
$is_use_magic = $argv[1];
/**
 * 构造函数使用类名
 */
class ClassOne
{
    public function classOne()
    {
        # code...
    }
}
/**
 * 构造函数使用魔术函数__construct
 */
class ClassTwo
{
    public function __construct()
    {
        # code...
    }
}
$a = getmicrotime();
if ($is_use_magic === &#39;no_magic&#39;) {
    new ClassOne();
}else {
    new ClassTwo();
}
$b = getmicrotime();
echo  ($b-$a) . "\n";

PHP5.6不使用魔術方法資料如下,單位微秒μs

// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 construct
// 运行数据统计脚本
sh analysis ./logs/__construct_no_magic_php5.log 10000
// 结果
avg: 34μs
max: 483μs
min: 26μs
PHP5.6使用魔術方法資料如下,單位微秒μs
// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 construct
// 运行数据统计脚本
sh analysis ./logs/__construct_magic_php5.log 10000
// 结果
avg: 28μs
max: 896μs
min: 20μs
PHP7.0不使用魔術方法資料如下,單位微秒μs
// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php construct
// 运行数据统计脚本
sh analysis ./logs/__construct_no_magic_php.log 10000
// 结果
avg: 19μs
max: 819μs
min: 13μs

PHP7.0使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php construct
// 运行数据统计脚本
sh analysis ./logs/__construct_magic_php.log 10000
// 结果
avg: 14μs
max: 157μs
min: 10μs

透過上面的資料我們可以看出:

使用__construct作為建構子的腳本執行的平均時間是要快於使用類別名稱作為建構子的,大概快5到6微秒,不論是在php5.6還是php7.0。

__call


#接著,我們來看看__call的實驗,php腳本如下:

<?php
/**
 * 魔术方法性能探索
 *
 * 构造函数
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
require(&#39;./function.php&#39;);
if (!isset($argv[1])) {
    die(&#39;error: variable is_use_magic is empty&#39;);
}
$is_use_magic = $argv[1];
/**
 * 构造函数使用类名
 */
class ClassOne
{
    public function __construct()
    {
        # code...
    }
    public function test()
    {
        # code...
    }
}
/**
 * 构造函数使用魔术函数__construct
 */
class ClassTwo
{
    public function __construct()
    {
        # code...
    }
    public function __call($method, $argus)
    {
        # code...
    }
}
$a = getmicrotime();
if ($is_use_magic === &#39;no_magic&#39;) {
    $instance = new ClassOne();
    $instance->test();
}else {
    $instance = new ClassTwo();
    $instance->test();
}
$b = getmicrotime();
echo  ($b-$a) . "\n";
PHP5.6不使用魔術方法資料如下,單位微秒μs
// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 call
// 运行数据统计脚本
sh analysis ./logs/__call_no_magic_php5.log 10000
// 结果
avg: 27μs
max: 206μs
min: 20μs
PHP5.6使用魔術方法資料如下,單位微秒μs

// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 call
// 运行数据统计脚本
sh analysis ./logs/__call_magic_php5.log 10000
// 结果
avg: 29μs
max: 392μs
min: 22μs

PHP7.0不使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php call
// 运行数据统计脚本
sh analysis ./logs/__call_no_magic_php.log 10000
// 结果
avg: 16μs
max: 256μs
min: 10μs

PHP7.0使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php call
// 运行数据统计脚本
sh analysis ./logs/__call_magic_php.log 10000
// 结果
avg: 18μs
max: 2459μs
min: 11μs

透過上面的資料我們可以看出:

使用__call的腳本執行的平均時間是慢於不使用,大概慢2微秒,不論是在php5.6還是php7.0。

__callStatic


#接著,我們來看看__callStatic的實驗,php腳本如下:

<?php
/**
 * 魔术方法性能探索
 *
 * 静态重载函数
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
require(&#39;./function.php&#39;);
if (!isset($argv[1])) {
    die(&#39;error: variable is_use_magic is empty&#39;);
}
$is_use_magic = $argv[1];
/**
 * 存在test静态方法
 */
class ClassOne
{
    public function __construct()
    {
        # code...
    }
    public static function test()
    {
        # code...
    }
}
/**
 * 使用重载实现test
 */
class ClassTwo
{
    public function __construct()
    {
        # code...
    }
    public static function __callStatic($method, $argus)
    {
        # code...
    }
}
$a = getmicrotime();
if ($is_use_magic === &#39;no_magic&#39;) {
    ClassOne::test();
}else {
    ClassTwo::test();
}
$b = getmicrotime();
echo  ($b-$a) . "\n";
PHP5.6不使用魔術方法資料如下,單位微秒μs
// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 callStatic
// 运行数据统计脚本
sh analysis ./logs/__callStatic_no_magic_php5.log 10000
// 结果
avg: 25μs
max: 129μs
min: 19μs
PHP5.6使用魔術方法資料如下,單位微秒μs

// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 callStatic
// 运行数据统计脚本
sh analysis ./logs/__callStatic_magic_php5.log 10000
// 结果
avg: 28μs
max: 580μs
min: 20μs

PHP7.0不使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php callStatic
// 运行数据统计脚本
sh analysis ./logs/__callStatic_no_magic_php.log 10000
// 结果
avg: 14μs
max: 130μs
min: 9μs

PHP7.0使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php callStatic
// 运行数据统计脚本
sh analysis ./logs/__callStatic_magic_php.log 10000
// 结果
avg: 14μs
max: 159μs
min: 10μs

透過上面的資料我們可以看出:

在php5.6中使用__callStatic的腳本執行的平均時間是要慢於不使用,大概慢3微秒;在php7.0中使用__callStatic的腳本執行的平均時間是要大致等於不使用__callStatic的;

__set


接著,我們來看看__set的實驗,php腳本如下:

<?php
/**
 * 魔术方法性能探索
 *
 * 设置私有属性__set
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
require(&#39;./function.php&#39;);
if (!isset($argv[1])) {
    die(&#39;error: variable is_use_magic is empty&#39;);
}
$is_use_magic = $argv[1];
/**
 * 实现公共方法设置私有属性
 */
class ClassOne
{
    /**
     * 私有属性
     *
     * @var string
     */
    private $someVariable = &#39;private&#39;;
    public function __construct()
    {
        # code...
    }
    public function setSomeVariable($value = &#39;&#39;)
    {
        $this->someVariable = $value;
    }
}
/**
 * 使用_set设置私有属性
 */
class ClassTwo
{
    /**
     * 私有属性
     *
     * @var string
     */
    private $someVariable = &#39;private&#39;;
    public function __construct()
    {
        # code...
    }
    public function __set($name = &#39;&#39;, $value = &#39;&#39;)
    {
        $this->$name = $value;
    }
}
$a = getmicrotime();
if ($is_use_magic === &#39;no_magic&#39;) {
    $instance = new ClassOne();
    $instance->setSomeVariable(&#39;public&#39;);
}else {
    $instance = new ClassTwo();
    $instance->someVariable = &#39;public&#39;;
}
$b = getmicrotime();
echo  ($b-$a) . "\n";
PHP5.6不使用魔術方法資料如下,單位微秒μs
// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 set
// 运行数据统计脚本
sh analysis ./logs/__set_no_magic_php5.log 10000
// 结果
avg: 31μs
max: 110μs
min: 24μs
PHP5.6使用魔術方法資料如下,單位微秒μs

// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 set
// 运行数据统计脚本
sh analysis ./logs/__set_magic_php5.log 10000
// 结果
avg: 33μs
max: 138μs
min: 25μs

PHP7.0不使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php set
// 运行数据统计脚本
sh analysis ./logs/__set_no_magic_php.log 10000
// 结果
avg: 15μs
max: 441μs
min: 11μs

PHP7.0使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php set
// 运行数据统计脚本
sh analysis ./logs/__set_magic_php.log 10000
// 结果
avg: 17μs
max: 120μs
min: 11μs

透過上面的資料我們可以看出:

使用__set的腳本執行的平均時間是要慢於不使用,大概慢2微秒,不論是在php5.6還是php7.0。

__get


#接著,我們來看看__get的實驗,php腳本如下:

<?php
/**
 * 魔术方法性能探索
 *
 * 读取私有属性__get
 *
 * @author TIGERB <https://github.com/TIGERB>
 */
require(&#39;./function.php&#39;);
if (!isset($argv[1])) {
    die(&#39;error: variable is_use_magic is empty&#39;);
}
$is_use_magic = $argv[1];
/**
 * 实现公共方法获取私有属性
 */
class ClassOne
{
    /**
     * 私有属性
     *
     * @var string
     */
    private $someVariable = &#39;private&#39;;
    public function __construct()
    {
        # code...
    }
    public function getSomeVariable()
    {
        return $this->someVariable;
    }
}
/**
 * 使用_get获取私有属性
 */
class ClassTwo
{
    /**
     * 私有属性
     *
     * @var string
     */
    private $someVariable = &#39;private&#39;;
    public function __construct()
    {
        # code...
    }
    public function __get($name = &#39;&#39;)
    {
        return $this->$name;
    }
}
$a = getmicrotime();
if ($is_use_magic === &#39;no_magic&#39;) {
    $instance = new ClassOne();
    $instance->getSomeVariable();
}else {
    $instance = new ClassTwo();
    $instance->someVariable;
}
$b = getmicrotime();
echo  ($b-$a) . "\n";
PHP5.6不使用魔術方法資料如下,單位微秒μs
// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 get
// 运行数据统计脚本
sh analysis ./logs/__get_no_magic_php5.log 10000
// 结果
avg: 28μs
max: 590μs
min: 20μs
PHP5.6使用魔術方法資料如下,單位微秒μs

// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 get
// 运行数据统计脚本
sh analysis ./logs/__get_magic_php5.log 10000
// 结果
avg: 28μs
max: 211μs
min: 22μs

PHP7.0不使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php get
// 运行数据统计脚本
sh analysis ./logs/__get_no_magic_php.log 10000
// 结果
avg: 16μs
max: 295μs
min: 10μs

PHP7.0使用魔術方法資料如下,單位微秒μs

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php get
// 运行数据统计脚本
sh analysis ./logs/__get_magic_php.log 10000
// 结果
avg: 19μs
max: 525μs
min: 12μs

透過上面的資料我們可以看出:

在php5.6中使用__get的腳本執行的平均時間是要大致等於不使用__get的;在php7.0中使用__get的腳本執行的平均時間是要慢於不使用,大概慢3微秒。


結語


#這裡主要測試了__construct(), __call(), __callStatic() , __get(), __set() 這五個常用的且可有其他實現方式代替的魔法函數。透過上面的測試再回來解答我的疑惑

######魔術方法真的表現比較差嗎? ######答案:除了使用__construct之外,這裡使用其他的魔法方法的時間大致慢10微秒以內。 ###############PHP7裡使用魔術方法的表現還是有問題嗎? ######答案:在PHP7中使用與不使用魔術方法之間的差異和在PHP5.6中近乎一致。 ###############我們應該如何合理的使用魔術方法? ###

答:透過整個測試我們可以看出使不使用魔法方法這之間的執行時間差異大致都是在10微秒以內的,所以如果魔法方法可以很好的節省我們的開發成本和優化我們的程式碼結構,我們應該可以考慮犧牲掉這不到10微秒。而__construct是要快的,所以使用__construct應該沒什麼異議。


以上是PHP常用魔術方法的效能探究的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn