【问题标题】:Use of php variable $_ (dollar sign followed by an underscore)php 变量 $_ 的使用(美元符号后跟下划线)
【发布时间】:2014-07-25 15:26:36
【问题描述】:

如果在foreach($array as $key => $value) 中不需要$value,我可以在foreach 循环中使用$_ 作为虚拟变量,这真的是真的吗?除了PHP syntax formatting,我找不到任何有用的信息来证明这一点。

当不使用值时,foreach 循环有一种特殊情况 循环内。在这种情况下,虚拟变量 $_(下划线)是 使用:

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

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

【问题讨论】:

  • 测试时间比询问时间短
  • 你试过foreach(array_keys($GLOBALS['TCA']) as $table) 吗?当然,仅使用未使用的值变量可能会减少资源密集度。
  • 我实际上有一个array($key => $arrayforlateruse, ... , ...)$arrayforlateruse 是现在不需要的变量。现在我知道放置$_ 没有任何效果。
  • 让我希望在 PHP 中有一个约定,在这种情况下使用 $_ 必须提供一个变量,但它不会被使用 - 类似于 Go,但是在 Go未使用的变量会导致错误; PHP 不必那么严格,但使用 $_ 可能是 linter 和 IDE 的信号,表明有意不使用变量,并且他们可以禁用此变量的“未使用变量”警告。

标签: php loops variables foreach naming-conventions


【解决方案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中使用后保持定义;这不是某种奇怪的“局部”变量。

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

或多或少随机测试和咆哮

n.b.我认为需要最近的 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 微秒

因此,如果其中一个版本有望为您节省 5 分钟的时间,例如每年五分钟的抓挠、寻找错误或客户支持,那么使用 那个 版本可能会证明是值得投资。

另一方面,如果您确实需要称为几十亿次的东西,以便将这些微不足道的微秒加起来值得处理,那么您最好花一些时间在将该部分代码移植(或已经移植)到一种语言,这种语言要么天生就更快,要么可以大规模并行化——可能是 C 或 Erlang;或重新考虑架构(例如,守护进程以节省开销,使用存储过程将麻烦转移到 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>";
    }
    

    【讨论】:

      【解决方案3】:

      正如其他人所说,$_ 是一个有效的变量名。这似乎是 Typo3 编码指南,虽然 $_ 没有被使用,但 foreach 需要 value 变量。如果您不需要值而是键,为什么要循环值?这看起来很骇人听闻。您可以将键作为值。我只会使用:

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

      【讨论】:

      • "如果你不需要这个值,为什么要使用 foreach?" ...但您仍在使用foreach
      • 是的,我收到了value
      【解决方案4】:

      来自Basics

      PHP 中的变量由一个美元符号后跟变量名表示。变量名区分大小写。

      变量名称遵循与 PHP 中其他标签相同的规则。有效的变量名称以字母或下划线开头,后跟任意数量的字母、数字或下划线。

      所以$_ 只是一个任意变量。使用$_$value 之间确实没有区别,只是$_ 只是一种传统的方式来表示一个实际上并没有在循环中使用的值。

      注意这一点

      $foo = array('a' => 1, 'b' => 2, 'c' => 3);
      foreach ($foo as $key => $_) echo $_;
      

      输出

      123
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-17
        • 2012-09-05
        • 2011-12-17
        • 2012-07-31
        • 1970-01-01
        相关资源
        最近更新 更多