使用 php 变量 $_ (美元符号后跟下划线)或多或少随机测试和咆哮PHP 7.2 更新

如果不需要 in,我真的可以在循环中用作虚拟变量吗?除了PHP语法格式之外,我找不到任何有用的信息来证明这一点。$_foreach$valueforeach($array as $key => $value)

对于 foreach 循环,当值未在循环内部使用时,有一种特殊情况。在本例中,使用虚拟变量 $_ (下划线):

foreach ($GLOBALS['TCA'] as $table => $_) { // Do something with $table }

这样做是出于性能原因,因为它比调用array_keys()并循环访问其结果更快。


答案 1

“_”是一个有效的变量名字符,因此您可以像使用任何其他变量一样使用它,并且没有特殊意义;这不是Perl。

<?php
    $_ = "Hello";
    $__ = "World";
    $___ = "foo";

    print "{$_}, {$__}, {$___}\n";
?>

将按预期输出“Hello, World, foo”。也

foreach ( [ 'a' => 'Alpha', 'b' => 'Beta', 'c' => 'Gamma' ] as $letter => $_ ) {
    print $letter;
}
print $_;

将输出 “abcGamma”,表明变量在 使用于 ;它不是某种奇怪的“局部”变量。$_foreach

至于表演,我不认为这有什么区别,但这是你的决定。相反,我会尽量不使用全局变量,以避免污染全局范围。

或多或少随机测试和咆哮

注意:我认为需要最近的PHP

随时更正/添加/提出改进建议

define('INNER_LOOP', 10000);
define('OUTER_LOOP', 10);

$TCA    = [
    'customers' => '',
    'relations' => '',
    'invoices'  => '',
    'books'     => '',
    'parts'     => '',
    'records'   => '',
    'calories'  => '',
    'bounties'  => '',
    'cats'      => '',
    'cowabunga' => '',
    'amenities' => '',
];

$tests  = [
    "foreach access to global" => function() {
        global $TCA;
        for ($i = 0; $i < INNER_LOOP; $i++) {
            foreach ($TCA as $table => $_) {
                $t = $table . 'x';
            }
        }
    },
    "foreach access to GLOBALS" => function() {
        for ($i = 0; $i < INNER_LOOP; $i++) {
            foreach ($GLOBALS['TCA'] AS $table => $_) {
                $t = $table . 'x';
            }
        }
    },
    "passing parameter" => function($TCA) {
        for ($i = 0; $i < INNER_LOOP; $i++) {
            foreach ($TCA AS $table => $_) {
                $t = $table . 'x';
            }
        }
    },
    "passing parameter and array_keys" => function($TCA) {
        $keys = array_keys($TCA);
        for ($i = 0; $i < INNER_LOOP; $i++) {
            foreach ($keys AS $table) {
                $t = $table . 'x';
            }
        }
    },
    "walking passed parameter w/lambda" => function($TCA) {
        for ($i = 0; $i < INNER_LOOP; $i++) {
            array_map(
                function($table) {
                    $t = $table . 'x';
                },
                array_keys($TCA)
            );
        }
    },
    "walking passed parameter w/ anon func" => function($TCA) {
        $handler = function($table) {
                    $t = $table . 'x';
                };
        $keys = array_keys($TCA);
        for ($i = 0; $i < INNER_LOOP; $i++) {
            array_map($handler, $keys);
        }
    },


];

function timeFunc($function, $obj) {
  $time   = microtime(true);
  for ($i = 0; $i < OUTER_LOOP; $i++) {
    $function($obj);
  }
  return (microtime(true) - $time);
}

foreach ($tests as $name => $test) {
    print "$name: " . timeFunc($test, $TCA) . "\n";
    flush();
}

这些是我的结果,格式化和排序:

- passing parameter and array_keys:      0.04573917388916
- foreach access to global:              0.067629098892212
- passing parameter:                     0.08098292350769
- foreach access to GLOBALS:             0.082289934158325
- walking passed parameter w/ anon func: 1.6233508586884
- walking passed parameter w/lambda:     1.6796138286591

有两件事需要注意:在最快和最慢之间,我的差异大约是四十倍但是,超过十万个呼叫的差异是1.63秒,这意味着在较快和较慢的版本之间进行一次呼叫需要16.3微秒

因此,如果其中一个版本有望为您节省资金,例如,每年五分钟的挠头,错误搜寻或客户支持,那么选择版本很可能是值得的投资。

另一方面,如果你真的需要一些叫做几十亿次的东西,这样那些微不足道的微秒加起来就值得处理,那么你最好花一些时间将这部分代码移植(或移植)到一种语言上,这种语言要么天生更快,要么可以大规模并行化 - 也许是C, 或二郎;或者重新思考体系结构(例如,守护进程以节省开销,使用存储过程将麻烦卸载到RDBMS,缓存结果等)。

PHP 7.2 更新

以下是 PHP 7.2.19 在较新的 64 位计算机上的结果:

passing parameter and array_keys        0.57718586921692
foreach access to global                0.65028595924377
passing parameter                       0.65098810195923
foreach access to GLOBALS               0.69678092002869
walking passed parameter w/ anon func   0.84391593933105
walking passed parameter w/lambda       1.0423438549042

请注意,最快和最慢之间的差异现在小于系数2;因此,“使用最清晰,最容易理解的代码”的论点现在更加强烈。


答案 2

下面的测试表明,在这种情况下用作变量名称似乎与使用任何其他变量名称没有任何区别。该值仍存储在变量中。$_

$tmp = array(1=>"one", 2=>"two", 3=>"three", 4=>"four", 5=>"five");
foreach ($tmp as $num=>$_) {
        echo "num is $num; dummy is $_<br>";
}

推荐