web-dev-qa-db-ja.com

php変数$ _の使用(ドル記号とそれに続くアンダースコア)

foreach($array as $key => $value)$_が必要ない場合、foreachループで$valueをダミー変数として使用できるのは本当に本当ですか? PHP構文フォーマット を除いて、これを証明する有用な情報は見つかりませんでした。

値がループ内で使用されていない場合、foreachループには特別なケースがあります。この場合、ダミー変数$ _(アンダースコア)が使用されます。

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

これは、array_keys()を呼び出してその結果をループするよりも高速であるため、パフォーマンス上の理由で行われます。

14
BalticMusicFan

「_」は有効な変数名文字であるため、他の変数と同じように使用でき、特別な意味はありません。これは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

注意する必要がある2つのこと:最も速いものと最も遅いものの間で、私は約40回の違いがあります。 しかし10万回の呼び出しとの差は1.63秒です。つまり、高速バージョンと低速バージョンの間の1回の呼び出しで16.3 マイクロ秒になります。

したがって、これらのバージョンの1つが、たとえば、年間5分間の頭を悩ませる、バグハンティング、またはカスタマーサポートを節約する見込みがある場合は、thatバージョンは価値のある投資を証明します。

一方、本当に数billion回と呼ばれるものが必要な場合は、それらのわずかなマイクロ秒が合計して取り組む価値のあるものになります。 dコードのそのセクションを、本質的に高速であるか、大規模に並列化できる言語(CまたはErlangなど)に移植する(または移植した)ことに時間を費やしたほうがよいでしょう。またはアーキテクチャを再考します(たとえば、プロセスをデーモン化してオーバーヘッドを節約する、ストアドプロシージャを使用して、面倒な作業をRDBMSにオフロードする、結果をキャッシュするなど)。

PHP 7.2の更新

これらは、新しい64ビットマシンでのPHP 7.2.19の結果です。

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倍未満になっていることに注意してください。したがって、「最も明確で理解しやすいコードを使用する」という議論はさらに強力になりました。

17
LSerni

以下のテストは、この状況で変数名として$_を使用することは、他の変数名を使用することと何ら変わらないように見えることを示しています。値は引き続き変数に格納されます。

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

から 基本

PHPの変数は、ドル記号とそれに続く変数名で表されます。変数名は大文字と小文字が区別されます。

変数名は、PHPの他のラベルと同じルールに従います。有効な変数名は、文字またはアンダースコアで始まり、その後に任意の数の文字、数字、またはアンダースコアが続きます。

したがって、$_は単なる任意の変数です。 $_$valueの使用に違いはありませんが、$_は、ループ内で実際に使用されていない値を示す従来の方法にすぎません。

これに注意してください

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

出力

123
1
p.s.w.g

他の人が述べているように$_は有効な変数名です。これはTypo3のコーディングガイドラインのようです。値が必要ないのに、なぜforeachなのですか?それはハックに見えます。キーを値として取得できます。私はただ使用します:

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