效能往往是衡量程式碼很重要的一個標準。我們日常編碼中常會用到一些魔術方法,這些PHP提供的魔術方法是否會影響我們程式的表現呢?是否需要減少魔術方法 的使用?本文將透過測試對比來了解魔術方法對表現的影響。
疑惑
魔術方法真的表現比較差嗎?
PHP7裡使用魔術方法的表現還是有問題嗎?
我們應該如何合理的使用魔術方法?
方案
面對我的疑惑,我的方案是:
統計對比使用魔術方法和不使用魔術方法腳本執行的時間差異
PHP5.6.26-1 下連續執行腳本n次
統計執行時間的平均值/最小值/最大值
PHP7.0.12-2 下連續執行腳本n次
統計執行時間的平均值/最小值/最大值
測試
__construct
首先我們先來看看建構子__construct的實驗,php腳本如下:
<?php /** * 魔术方法性能探索 * * 构造函数 * * @author TIGERB <https://github.com/TIGERB> */ require('./function.php'); if (!isset($argv[1])) { die('error: variable is_use_magic is empty'); } $is_use_magic = $argv[1]; /** * 构造函数使用类名 */ class ClassOne { public function classOne() { # code... } } /** * 构造函数使用魔术函数__construct */ class ClassTwo { public function __construct() { # code... } } $a = getmicrotime(); if ($is_use_magic === 'no_magic') { new ClassOne(); }else { new ClassTwo(); } $b = getmicrotime(); echo ($b-$a) . "\n";
// 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中连续调用脚本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中连续调用脚本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中连续调用脚本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('./function.php');
if (!isset($argv[1])) {
die('error: variable is_use_magic is empty');
}
$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 === 'no_magic') {
$instance = new ClassOne();
$instance->test();
}else {
$instance = new ClassTwo();
$instance->test();
}
$b = getmicrotime();
echo ($b-$a) . "\n";
// 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中连续调用脚本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('./function.php');
if (!isset($argv[1])) {
die('error: variable is_use_magic is empty');
}
$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 === 'no_magic') {
ClassOne::test();
}else {
ClassTwo::test();
}
$b = getmicrotime();
echo ($b-$a) . "\n";
// 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中连续调用脚本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('./function.php');
if (!isset($argv[1])) {
die('error: variable is_use_magic is empty');
}
$is_use_magic = $argv[1];
/**
* 实现公共方法设置私有属性
*/
class ClassOne
{
/**
* 私有属性
*
* @var string
*/
private $someVariable = 'private';
public function __construct()
{
# code...
}
public function setSomeVariable($value = '')
{
$this->someVariable = $value;
}
}
/**
* 使用_set设置私有属性
*/
class ClassTwo
{
/**
* 私有属性
*
* @var string
*/
private $someVariable = 'private';
public function __construct()
{
# code...
}
public function __set($name = '', $value = '')
{
$this->$name = $value;
}
}
$a = getmicrotime();
if ($is_use_magic === 'no_magic') {
$instance = new ClassOne();
$instance->setSomeVariable('public');
}else {
$instance = new ClassTwo();
$instance->someVariable = 'public';
}
$b = getmicrotime();
echo ($b-$a) . "\n";
// 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中连续调用脚本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('./function.php');
if (!isset($argv[1])) {
die('error: variable is_use_magic is empty');
}
$is_use_magic = $argv[1];
/**
* 实现公共方法获取私有属性
*/
class ClassOne
{
/**
* 私有属性
*
* @var string
*/
private $someVariable = 'private';
public function __construct()
{
# code...
}
public function getSomeVariable()
{
return $this->someVariable;
}
}
/**
* 使用_get获取私有属性
*/
class ClassTwo
{
/**
* 私有属性
*
* @var string
*/
private $someVariable = 'private';
public function __construct()
{
# code...
}
public function __get($name = '')
{
return $this->$name;
}
}
$a = getmicrotime();
if ($is_use_magic === 'no_magic') {
$instance = new ClassOne();
$instance->getSomeVariable();
}else {
$instance = new ClassTwo();
$instance->someVariable;
}
$b = getmicrotime();
echo ($b-$a) . "\n";
// 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中连续调用脚本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() 這五個常用的且可有其他實現方式代替的魔法函數。透過上面的測試再回來解答我的疑惑
答:透過整個測試我們可以看出使不使用魔法方法這之間的執行時間差異大致都是在10微秒以內的,所以如果魔法方法可以很好的節省我們的開發成本和優化我們的程式碼結構,我們應該可以考慮犧牲掉這不到10微秒。而__construct是要快的,所以使用__construct應該沒什麼異議。
以上是PHP常用魔術方法的效能探究的詳細內容。更多資訊請關注PHP中文網其他相關文章!