PHP foreachは元の配列値を変更します


143

私は多次元配列で非常に新しいので、これは私に大きな時間を費やしています。

私の配列は次のとおりです:

$fields = array(
    "names" => array(
         "type"         => "text",
         "class"        => "name",
         "name"         => "name",
         "text_before"  => "name",
         "value"        => "",
         "required"     => true,
    )
)

次に、これらの入力が必要かどうかが入力されているかどうかをチェックする機能を取得しました。

function checkForm($fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

今私の問題はこの行です

$fields[$field]['value'] = "Some error";

これを返すため、元の配列の内容を変更したいのですが、foreachループで現在の配列の名前(この例では名前)を取得するにはどうすればよいですか?



1
どんなに新しいあなたが(またはにするために使用) -これはあなたがPHPのドキュメントから読み取ることができるものは次のとおりです。php.net/manual/en/control-structures.foreach.php
ニコライ・イワノフ

回答:


261

PHPでは、参照渡し(&)については議論の余地があります。なぜそれが必要で、結果をテストするのかわからない場合は、使用しないことをお勧めします。

私は以下を行うことをお勧めします:

foreach ($fields as $key => $field) {
    if ($field['required'] && strlen($_POST[$field['name']]) <= 0) {
        $fields[$key]['value'] = "Some error";
    }
}

したがって、基本的には$field、値が必要な場合、および$fields[$key]データを変更する必要がある場合に使用します。


これでうまくいきます。最初にこのようなものを試してみましたが、私はいくつかの場所を台無しにしたと思います:)これであなたの例を1000回使用し、決して忘れません!:)
Jeppe 2013

それが助けてうれしい。また、私がリンクした記事とforeachの公式ドキュメント(php.net/manual/ro/control-structures.foreach.php)を読むことをお勧めします
Vlad Preda

4
結論:配列/変数を変更する場合は、参照を使用する必要があります。より速く、よりクリーンで読みやすくなります。
Lulu、

2
なぜ参照で渡すforeachことは議論の余地があるのでしょうか?これは、隠れた副作用などを伴う関数呼び出しのようなものではありません。
UncaAlby 2017年

1
「参照渡しはしない」や「参照渡しは悪」ではなく、「参照渡し(&)は議論の余地がある」と言ってくれてありがとう。炎の戦争を開始する可能性が低くなります。:)
ビーンをショーン

162

使用&

foreach($arr as &$value)
{
     $value = $newVal;
}

&配列の値を参照として渡し、変数の新しいインスタンスを作成しません。したがって、参照を変更すると、元の値が変更されます。

http://php.net/manual/en/language.references.pass.php

2018年の編集
この回答はインターネット上の多くの人に好まれているようです。そのため、私は情報と注意事項をさらに追加することにしました。
参照渡しforeach(または関数)は簡潔で短い解決策ですが、多くの初心者にとって、これは危険な落とし穴になる可能性があります。

  1. PHPのループには、独自のスコープはありません。-@マーク・アメリー

    変数が同じスコープで再利用されている場合、これは深刻な問題になる可能性があります。別のSOの質問は、それが問題である理由をうまく説明しています。

  2. foreachはPHP 5の内部配列ポインターに依存しているため、ループ内で変更すると、予期しない動作が発生する可能性があります。-foreachのPHPドキュメント

    同じループでの反復中にレコードの設定を解除したり、ハッシュ値(キー)を変更したりすると、PHP <7で予期しない動作が発生する可能性があります。配列自体が参照の場合、問題はさらに複雑になります。

  3. Foreachパフォーマンス。
    一般に、コピーオンライト機能により、PHPは値渡しを優先します。つまり、PHPのコピーを変更する必要がない限り、内部的にPHPが重複データを作成することはありません。参照渡しかどうかは議論の余地がありますforeachパフォーマンスが向上するます。常にそうであるので、特定のシナリオをテストし、どのオプションがより少ないメモリとCPU時間を使用するかを決定する必要があります。詳細については、以下にリンクされているNikiCによるSOの投稿を参照してください。

  4. コードの可読性。
    PHPで参照を作成することは、すぐに手に負えなくなるものです。あなたが初心者であり、自分がやっていることを完全に制御できない場合は、参照を避けてください。&オペレーターの詳細については、このガイドを参照してください:参照— PHPでこの記号は何を意味しますか?
    PHP言語のこの部分について詳しく知りたい方のために:PHPリファレンスの説明

@NikiCによるPHP foreachループの内部ロジックの非常に優れた技術的説明:
PHPの「foreach」は実際にどのように機能しますか?


リストされた問題は別として、反復後に参照変数が使用できなくなることを確実にするためunset($value);に、foreach閉じ括弧の後に追加することをお勧めします。 3v4l.org/2V2AQ
fyrye

15

使用foreach($fields as &$field){-元の配列で作業します。

参照渡しについては、こちらをご覧ください。


@RBA plsは上記の回答を参照しています-詳細と更新があります-私はしばらくphpを使用していないので、これに関する更新はありません
k102

1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

これは私が参照渡しを提案するものです


このテクニックは、元の変数の値を変更するために使用されます。PHPは値渡しテクニックをサポートしているためです。変数の前に「&」文字を追加して、参照によって渡される値を指定する必要があります
Sagar Kadam

1
では、なぜまだ戻るの$fieldsですか?
MAZux 2018年

これは、提案された3つの中で最悪の答えです。この答えに出くわした人は、データを変更して返すように関数を設計しないでください。原作者のために:あなたは、このソリューションが他のものよりも良いだろう、なぜ任意の説明を提供し、またはしていない、それはすべて...でどのように動作するか
Dharman

-6

これを試して

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }

3
こんなことしないで。私はあなたのコードで少なくとも2つの問題を見ることができます:$ fieldへの代入は機能しません(これを行うと$ fields配列は変更されません)、そして$ fieldは配列ではなく特異なフィールドを返します。
Staplerfahrer 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.