首頁  >  文章  >  後端開發  >  PHP 魔法函數效能程式碼詳細分析

PHP 魔法函數效能程式碼詳細分析

黄舟
黄舟原創
2017-03-09 09:56:371351瀏覽

曾經記得鳥哥Laruence提過不建議使用”魔術方法”,自此之後一旦涉及使用魔術方法的地方,我都會下意識的想一下,這樣寫真的好嗎?由於這一到兩年來一直忙於工作和學習新的知識,所以在這道坎兒上一直沒有做深入的探索一直恍恍惚惚過去了,今年是我進行深入學習的一年,因此現在必須對這個問題做個了結了。我們先來看看鳥哥Laruence博客曾經提到的:

當我把PPT分享給公司的同事的時候, 會有人質疑, 魔術方法都不讓用?

優化的建議, 是建議, 是防止大家濫用, 肆無忌憚的用. 如果你能在寫代碼的時候, 能意識到, 什麼慢, 什麼快, 從而避免一些沒有必要的對魔術方法的調用, 那就是這個優化建議所追求的效果了

疑惑

  1. 魔術方法真的性能比較差嗎?

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

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

方案

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

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

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

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

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

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

目前個人能力有限,只能透過這種方式,如果你有更好的方案或建議可以告訴我,謝謝,haha~

測試

__construct

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

<?php
/**
 * 魔术方法性能探索
 *
 * 构造函数
 *
 * @author TIGERB <http://www.php.cn/;
 */

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不使用魔術方法數據如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 no_magic php5 construct
    
    // 运行数据统计脚本
    sh analysis ./logs/__construct_no_magic_php5.log 10000
    
    // 结果
    avg: 34μm
    max: 483μm
    min: 26μm
  • PHP5.6使用魔術方法資料如下,單位微秒μm

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

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 no_magic php construct
    
    // 运行数据统计脚本
    sh analysis ./logs/__construct_no_magic_php.log 10000
    
    // 结果
    avg: 19μm
    max: 819μm
    min: 13μm
  • PHP7.0使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 magic php construct
    
    // 运行数据统计脚本
    sh analysis ./logs/__construct_magic_php.log 10000
    
    // 结果
    avg: 14μm
    max: 157μm
    min: 10μm
透過上面的資料我們可以看出:

使用__construct作為建構子的腳本執行的平均時間是要快於使用類別名作為建構子的,

大概快5到6微秒 ,不論是在php5.6還是php7.0。

__call

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

<?php
/**
 * 魔术方法性能探索
 *
 * 构造函数
 *
 * @author TIGERB <http://www.php.cn/;
 */

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不使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 no_magic php5 call
    
    // 运行数据统计脚本
    sh analysis ./logs/__call_no_magic_php5.log 10000
    
    // 结果
    avg: 27μm
    max: 206μm
    min: 20μm
  • PHP5.6使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 magic php5 call
    
    // 运行数据统计脚本
    sh analysis ./logs/__call_magic_php5.log 10000
    
    // 结果
    avg: 29μm
    max: 392μm
    min: 22μm
  • PHP7.0不使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 no_magic php call
    
    // 运行数据统计脚本
    sh analysis ./logs/__call_no_magic_php.log 10000
    
    // 结果
    avg: 16μm
    max: 256μm
    min: 10μm
  • PHP7.0使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 magic php call
    
    // 运行数据统计脚本
    sh analysis ./logs/__call_magic_php.log 10000
    
    // 结果
    avg: 18μm
    max: 2459μm
    min: 11μm
透過上面的資料我們可以看出:

#使用__call的腳本執行的平均時間是要慢於不使用,

大概慢2微秒 ,不論是在php5.6還是php7.0。

__callStatic

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

<?php
/**
 * 魔术方法性能探索
 *
 * 静态重载函数
 *
 * @author TIGERB <http://www.php.cn/;
 */

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不使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 no_magic php5 callStatic
    
    // 运行数据统计脚本
    sh analysis ./logs/__callStatic_no_magic_php5.log 10000
    
    // 结果
    avg: 25μm
    max: 129μm
    min: 19μm
  • PHP5.6使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 magic php5 callStatic
    
    // 运行数据统计脚本
    sh analysis ./logs/__callStatic_magic_php5.log 10000
    
    // 结果
    avg: 28μm
    max: 580μm
    min: 20μm
  • PHP7.0不使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 no_magic php callStatic
    
    // 运行数据统计脚本
    sh analysis ./logs/__callStatic_no_magic_php.log 10000
    
    // 结果
    avg: 14μm
    max: 130μm
    min: 9μm
  • PHP7.0使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 magic php callStatic
    
    // 运行数据统计脚本
    sh analysis ./logs/__callStatic_magic_php.log 10000
    
    // 结果
    avg: 14μm
    max: 159μm
    min: 10μm
透過上面的資料我們可以看出:

#在php5.6中使用__callStatic的腳本執行的平均時間是要慢於不使用,

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

__set

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

<?php
/**
 * 魔术方法性能探索
 *
 * 设置私有属性__set
 *
 * @author TIGERB <http://www.php.cn/;
 */

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不使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 no_magic php5 set
    // 运行数据统计脚本
    sh analysis ./logs/__set_no_magic_php5.log 10000
    
    // 结果
    avg: 31μm
    max: 110μm
    min: 24μm
  • PHP5.6使用魔術方法資料如下,單位微秒μm

  • // PHP5.6中连续调用脚本10000次
    sh test 10000 magic php5 set
    // 运行数据统计脚本
    sh analysis ./logs/__set_magic_php5.log 10000
    
    // 结果
    avg: 33μm
    max: 138μm
    min: 25μm
  • PHP7.0不使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 no_magic php set
    // 运行数据统计脚本
    sh analysis ./logs/__set_no_magic_php.log 10000
    
    // 结果
    avg: 15μm
    max: 441μm
    min: 11μm
  • PHP7.0使用魔術方法資料如下,單位微秒μm

  • // PHP7.0中连续调用脚本10000次
    sh test 10000 magic php set
    // 运行数据统计脚本
    sh analysis ./logs/__set_magic_php.log 10000
    
    // 结果
    avg: 17μm
    max: 120μm
    min: 11μm
透過上面的資料我們可以看出:

使用__set的腳本執行的平均時間是要慢於不使用,

大概慢2微秒 ,不論是在php5. 6還是php7.0中。

__get

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

<?php
/**
 * 魔术方法性能探索
 *
 * 读取私有属性__get
 *
 * @author TIGERB <http://www.php.cn/;
 */

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不使用魔术方法数据如下,单位微秒μm

// PHP5.6中连续调用脚本10000次
sh test 10000 no_magic php5 get
// 运行数据统计脚本
sh analysis ./logs/__get_no_magic_php5.log 10000

// 结果
avg: 28μm
max: 590μm
min: 20μm
  • PHP5.6使用魔术方法数据如下,单位微秒μm

// PHP5.6中连续调用脚本10000次
sh test 10000 magic php5 get
// 运行数据统计脚本
sh analysis ./logs/__get_magic_php5.log 10000

// 结果
avg: 28μm
max: 211μm
min: 22μm
  • PHP7.0不使用魔术方法数据如下,单位微秒μm

// PHP7.0中连续调用脚本10000次
sh test 10000 no_magic php get
// 运行数据统计脚本
sh analysis ./logs/__get_no_magic_php.log 10000

// 结果
avg: 16μm
max: 295μm
min: 10μm
  • PHP7.0使用魔术方法数据如下,单位微秒μm

// PHP7.0中连续调用脚本10000次
sh test 10000 magic php get
// 运行数据统计脚本
sh analysis ./logs/__get_magic_php.log 10000

// 结果
avg: 19μm
max: 525μm
min: 12μm

通过上面的数据我们可以看出:

在php5.6中使用__get的脚本执行的平均时间是要大致等于不使用__get的;在php7.0中使用__get的脚本执行的平均时间是要慢于不使用, 大概慢3微秒

结语

这里主要测试了__construct(), __call(), __callStatic(), __get(), __set()这五个常用的且可有其他实现方式代替的魔法函数。通过上面的测试再回来解答我的疑惑

  1. 魔术方法真的性能比较差吗?

答:除了使用__construct之外,这里使用其他的魔法方法的时间大致慢10微妙以内。

  1. PHP7里使用魔术方法的性能还是存在问题吗?

答:在PHP7中使用与不使用魔术方法之间的差异和在PHP5.6中近乎一致。

  1. 我们应该如何合理的使用魔术方法?

答:通过整个测试我们可以看出使不使用魔法方法这之间的执行时间差异大致都是在10微妙以内的,所以如果魔法方法可以很好的节省我们的开发成本和优化我们的代码结构,我们应该可以考虑牺牲掉这不到10微妙。而__construct是要快的,所以使用__construct应该没什么异议。

  

以上是PHP 魔法函數效能程式碼詳細分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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