以前、バード兄弟のラルエンスが「魔法の方法」を使うのは推奨されないと言っていたのを思い出し、それ以来、魔法の方法が使われるたびに、これは良い写真だろうかと無意識に考えるようになりました。ここ1~2年は仕事と新しい知識の習得に忙しかったため、この道を深く探ることはなく、ぼんやりしていました。今年は私にとって深く勉強する年です。 、それで、今度はこの問題について調査する必要があります。まず、Bird Brother Laruence がかつて自身のブログで述べたことを見てみましょう:
PPT を社内の同僚と共有すると、魔法の手法の使用も許可されていないことに疑問を持つ人もいます
最適化?提案は提案であり、予防ではありません。誰もがそれを悪用し、不謹慎に使用します。コードを書くときに何が遅くて何が速いかを認識でき、それによって魔法のメソッドへの不要な呼び出しを避けることができれば、それがこの最適化提案が追求する効果です
その魔法の方法は本当に性能が悪いのでしょうか?
PHP7 のマジック メソッドのパフォーマンスにまだ問題がありますか?
魔法の方法を合理的に使用するにはどうすればよいですか?
私の疑問に直面した私の解決策は次のとおりです:
マジックメソッドを使用した場合と使用しない場合のスクリプト実行の時間差の統計的比較
PHP5 でのスクリプトの継続実行.6.26-1 n回
実行時間の平均/最小/最大値の統計
PHP7.0.12-2でスクリプトをn回連続実行
の統計的な平均/最小/最大値実行時間
現在、私の個人的な能力には限界があるので、より良い計画や提案があれば、教えてください、ありがとう、笑〜
まず第一に。 、コンストラクターを見てみましょう コンストラクトの実験、phpスクリプトは次のとおりです:
<?php /** * 魔术方法性能探索 * * 构造函数 * * @author TIGERB <http://www.php.cn/; */ 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はマジックメソッドを使用しません。データは次のとおりです。単位はマイクロ秒μ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 はマジックメソッドを使用します。データは次のとおりです。単位はマイクロ秒です
// 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 を使用したスクリプトの平均実行時間。コンストラクターは、php5.6 であっても php7.0 であっても、クラス名をコンストラクターとして使用するよりも高速であり、約 5 ~ 6 マイクロ秒です。
次に、呼び出しの実験を見てみましょう:
<?php /** * 魔术方法性能探索 * * 构造函数 * * @author TIGERB <http://www.php.cn/; */ 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 はマジックメソッドを使用しません。データは次のとおりです (マイクロ秒単位)。
// 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中连续调用脚本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中连续调用脚本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中连续调用脚本10000次 sh test 10000 magic php call // 运行数据统计脚本 sh analysis ./logs/call_magic_php.log 10000 // 结果 avg: 18μm max: 2459μm min: 11μm上記のデータからわかります:
約php5.6でもphp7.0でも2マイクロ秒
。callStatic
次に、callStatic の実験を見てみましょう。php スクリプトは次のとおりです。<?php /** * 魔术方法性能探索 * * 静态重载函数 * * @author TIGERB <http://www.php.cn/; */ 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μ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を使用したスクリプトの平均実行時間は、それよりも遅いです。 php7.0 で callStatic を使用した場合、
約 3 マイクロ秒set
次に、PHP スクリプトを見てみましょう。 <?php
/**
* 魔术方法性能探索
*
* 设置私有属性set
*
* @author TIGERB <http://www.php.cn/;
*/
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μ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 はマジックメソッドを使用しません。データは次のとおりです。単位はマイクロ秒です
// 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
php5.6 か php7.0 かにかかわらず、set を使用したスクリプトの平均実行時間は、set を使用しない場合よりも遅くなり、
約 2 ミクロン秒遅くなりますget
次に、get の実験を見てみましょう。php スクリプトは次のとおりです。
<?php /** * 魔术方法性能探索 * * 读取私有属性get * * @author TIGERB <http://www.php.cn/; */ 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不使用魔术方法数据如下,单位微秒μ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()这五个常用的且可有其他实现方式代替的魔法函数。通过上面的测试再回来解答我的疑惑
魔术方法真的性能比较差吗?
答:除了使用construct之外,这里使用其他的魔法方法的时间大致慢10微妙以内。
PHP7里使用魔术方法的性能还是存在问题吗?
答:在PHP7中使用与不使用魔术方法之间的差异和在PHP5.6中近乎一致。
我们应该如何合理的使用魔术方法?
答:通过整个测试我们可以看出使不使用魔法方法这之间的执行时间差异大致都是在10微妙以内的,所以如果魔法方法可以很好的节省我们的开发成本和优化我们的代码结构,我们应该可以考虑牺牲掉这不到10微妙。而construct是要快的,所以使用construct应该没什么异议。
以上がPHPマジック関数の性能を詳しく説明したサンプルコードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。