PHP foreach循环更改原始数组值

186
I am very new in multi-dimensional arrays, and this is causing me a lot of trouble.
My array is as follows:
$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循环中获取当前数组的名称(在此示例中为names)?


3
无论你是多么新(或者曾经是)——这是你可以从 PHP 文档中读到的内容:http://php.net/manual/en/control-structures.foreach.php。 - Nikolay Ivanov
5个回答

330

对我来说,你的链接和你的摘要相反。除了第一个答案之外,每个答案都说引用更快,而第一个答案适用于实际上不修改数组的实用用途。 - Noumenon
4
底线是:如果您要更改数组/变量,则应使用引用。这样做更快、更简洁且更易读。 - Lulu
2
我很好奇为什么在 foreach 中传递引用会引起争议?这不像是带有隐藏副作用的函数调用或其他什么东西。 - UncaAlby
1
谢谢您说“通过引用(&)传递参数是有争议的”,而不是“不要通过引用传递参数”或“通过引用传递参数是邪恶的”。这样不太可能引发争论。 :) - Sean the Bean
1
对我来说不起作用,年份为2020,PHP版本为7 :) - Vladimir Despotovic
显示剩余6条评论

228
使用 &
foreach($arr as &$value) {
    $value = $newVal;
}
unset($value);
& 作为数组的引用传递,不会创建变量的新实例。因此,如果更改引用,则原始值将更改。 传递引用的 PHP 文档 编辑 2018 这个答案似乎受到了很多人的青睐,这就是我决定添加更多信息和警告词语的原因。
虽然在 foreach(或函数)中使用引用传递是一种干净而简短的解决方案,但对于许多初学者来说,这可能是一个危险的陷阱。
  1. PHP中的循环没有自己的作用域。- @Mark Amery

    当变量在同一作用域内被重复使用时,这可能是一个严重的问题。另一个SO问题很好地说明了为什么会出现问题

  2. 由于foreach在PHP 5中依赖于内部数组指针,因此在循环中更改它可能会导致意外行为。- PHP文档对于foreach的解释。

    在PHP<7中,在同一循环中迭代期间取消记录或更改哈希值(键)可能会导致潜在的意外行为。如果数组本身是一个引用,则问题会变得更加复杂。

  3. foreach的性能。
    总的来说,由于拷贝写入特性,PHP更喜欢传值方式。这意味着在内部,PHP不会创建重复数据,除非需要更改其副本。关于在foreach中使用传递引用是否会提供任何性能改进,这是有争议的。与通常情况一样,您需要测试您的具体场景并确定哪个选项使用更少的内存和CPU时间。有关更多信息,请参见下面由NikiC链接的SO帖子。

  4. 代码可读性。
    在PHP中创建引用是一件很快就会失控的事情。如果您是初学者,并且没有完全掌握自己在做什么,最好远离引用。有关&运算符的更多信息,请查看此指南:引用-在PHP中这个符号代表什么?
    对于那些想要了解PHP语言的更多信息的人:PHP引用解释

@NikiC提供了一份非常好的技术解释,解释了PHP foreach循环的内部逻辑:
PHP的“foreach”实际上是如何工作的?


4
除了列出的问题外,我建议在foreach的结束括号后添加unset($value);,以确保引用变量在迭代之后不再可用。 https://3v4l.org/2V2AQ - Will B.
我建议在 unset($value); 行添加注释,强调其重要性。这已经给许多 PHP 开发人员带来了麻烦,并导致了大量的错误。 - rustyx
请注意:在第一个foreach语句中使用'&'设置所需的值后,您需要在每个后续的foreach语句中再次使用它('&'运算符),以便访问新创建的索引(如果有的话)及其值。 - undefined

21
使用foreach($fields as &$field){ - 这样您将使用原始数组进行操作。 这里有更多关于按引用传递的内容。

@RBA请参考上面的答案 - 它们有更多的细节和更新 - 我已经有一段时间没有使用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
2
那为什么还要返回 $fields 呢? - MAZux
这是三个建议中最糟糕的答案。对于那些偶然看到这个答案的人,请不要设计你的函数来直接改变数据并返回它。对于原作者:你没有提供任何解释,为什么这个解决方案会比其他解决方案更好,或者它如何工作。 - Dharman

-8

试试这个

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

5
不要这样做。我至少能看出你的代码存在两个问题: 将值赋给 $field 不起作用(当你这样做时,$fields 数组永远不会被修改), 并且 return $field 只返回单个字段,而不是数组。 - Jacob Bruinsma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接