Use of php variable $_ (dollar sign followed by an underscore)

假如想象 提交于 2020-12-25 01:49:13

问题


Is that really true that i can use $_ as a dummy variable in foreach loop if there is no need for $value in foreach($array as $key => $value)? I could not find any useful information that proves this except PHP syntax formatting.

There's a special case for foreach loops when the value is not used inside the loop. In this case the dummy variable $_ (underscore) is used:

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

This is done for performance reasons, as it is faster than calling array_keys() and looping on its result.


回答1:


"_" is a valid variable name character, so you can use it as you would any other variable and has no special significance; this isn't Perl.

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

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

will output "Hello, World, foo" as expected. Also,

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

will output "abcGamma", showing that the $_ variable remains defined after being used in the foreach; it's not some weird kind of "local" variable.

As for the performances, I don't think it makes much difference, but that's your call. Rather, I'd try and not use global variables, to avoid polluting the global scope.

Tests and rants more or less at random

n.b. a recent PHP required, I think

feel free to correct/add/suggest improvements

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();
}

These are my results, formatted and sorted:

- 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

Two things need noting: between the fastest and slowest I have a difference of about forty times. But the difference over one hundred thousand calls is 1.63 seconds, which means 16.3 microseconds for a single call between the faster and the slower versions.

So if one of these versions show promise of saving you, say, five minutes a year of head-scratching, bug-hunting or customer support, it's likely that going for that version will prove a worthwhile investment.

If, on the other hand, you really need something called several billion times, so that those paltry microseconds add up to something worth tackling, then probably you'd be better off investing some time in porting (or having ported) that section of code to a language which is either inherently faster or can be made to massively parallelize - maybe C, or Erlang; or re-thinking the architecture (e.g. daemonize a process to save on the overhead, use stored procedures to offload the hassle to the RDBMS, cache results, ...).

UPDATE FOR PHP 7.2

These are the results for PHP 7.2.19 on a newer 64bit machine:

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

Note that the difference between fastest and slowest is now less than a factor of 2; therefore, the argument for "go with the clearest, easiest to understand code" is now even stronger.




回答2:


The test below demonstrates that using $_ as a variable name in this situation doesn't seem to be any different from using any other variable name. The value is still stored in the variable.

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



回答3:


As others have stated $_ is a valid variable name. This seems to be Typo3 coding guidelines though the $_ is not being used, but the value variable is required for the foreach. Why loop the values if you don't need the values but the keys? That looks hackish. You can get the keys as values. I would just use:

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



回答4:


From Basics:

Variables in PHP are represented by a dollar sign followed by the name of the variable. The variable name is case-sensitive.

Variable names follow the same rules as other labels in PHP. A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.

So $_ is just an arbitrary variable. There's really no difference between using $_ and $value, except that $_ is just a conventional way to indicate a value that is not actually used inside the loop.

Notice that this

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

Outputs

123


来源:https://stackoverflow.com/questions/24046586/use-of-php-variable-dollar-sign-followed-by-an-underscore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!