184

I am very new in multi dimensional arrays, and this is bugging me big time.

My array is as following:

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

Then i got a function checking if these inputs are filled in, if they are required.

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

Now my problem is this line

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

I want to change the content of the original array, since i am returning this, but how do I get the name of the current array (names in this example) in my foreach loop?

Ahmed Syed
  • 1,179
  • 2
  • 18
  • 44
Jeppe
  • 2,163
  • 2
  • 14
  • 15
  • 2
    No matter how new you are (or used to be) - this is something you can read from the PHP documentation: http://php.net/manual/en/control-structures.foreach.php – Nikolay Ivanov Jul 29 '16 at 11:34

5 Answers5

328

In PHP, passing by reference (&) is ... controversial. I recommend not using it unless you know why you need it and test the results.

I would recommend doing the following:

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

So basically use $field when you need the values, and $fields[$key] when you need to change the data.

Vlad Preda
  • 9,780
  • 7
  • 36
  • 63
  • Nice, this works! Tried something like this first, but i guess i screwed up some place :) Now i will use your example a thousand times and never forget! :) – Jeppe Feb 22 '13 at 12:56
  • Glad it helped. Also, I recommend to read the article I linked, and also the official documentation for foreach ( http://php.net/manual/ro/control-structures.foreach.php ) – Vlad Preda Feb 22 '13 at 12:57
  • To me, your link says the opposite of your summary of it. Every answer but the first says reference is faster, and the first answer is for *non*practical uses that don't actually modify the array. – Noumenon Nov 08 '15 at 21:58
  • 4
    Bottom line: if you're going to change the array/variable - then you should use a reference. It's faster, cleaner and more readable. – Lulu Feb 10 '16 at 08:26
  • Like @Lulu says, and like the linked article clearly stated it, changing a variable by reference has no performance cost at all. You may edit the answer — you're quoting another answer wrongly IMO. – yves amsellem Apr 06 '16 at 07:58
  • @yvesamsellem: Not sure what you're reading, both the accepted answer and the one with the highest upvotes say that passing by value is as fast or faster than references. This is due to the copy-on-write functionality of the Zend engine, which you no longer use when you use references. – Vlad Preda Apr 06 '16 at 11:28
  • @VladPreda I read the highest upvoted answer, http://stackoverflow.com/a/3845530/535184, which states "If the function change the value of the variable passed, for practical purposes is the same as pass by reference than by value" – yves amsellem Apr 07 '16 at 15:20
  • 2
    I'm curious why passing by reference in a `foreach` should be controversial? It's not like it's a function call with hidden side effects or anything. – UncaAlby Mar 22 '17 at 20:43
  • 1
    Thank you for saying that "passing by reference (&) is ... controversial", rather than "don't pass by reference" or "passing by reference is evil". Less likely to start a flame war. :) – Sean the Bean Oct 03 '17 at 20:24
  • @SeantheBean - been there, done that. I edited the post a surprising number of times to get to this less inflamatory wording :-) – Vlad Preda Oct 09 '17 at 13:30
  • It doesn't work for me, year 2020, PHP version 7 :) – Vladimir Despotovic Nov 25 '20 at 17:23
227

Use &:

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

& passes a value of the array as a reference and does not create a new instance of the variable. Thus if you change the reference the original value will change.

PHP documentation for Passing by Reference

Edit 2018

This answer seems to be favored by a lot of people on the internet, which is why I decided to add more information and words of caution.
While pass-by-reference in foreach (or functions) is a clean and short solution, for many beginners this might be a dangerous pitfall.

  1. Loops in PHP don't have their own scope. - @Mark Amery

    This could be a serious problem when the variables are being reused in the same scope. Another SO question nicely illustrates why that might be a problem.

  2. As foreach relies on the internal array pointer in PHP 5, changing it within the loop may lead to unexpected behavior. - PHP docs for foreach.

    Unsetting a record or changing the hash value (the key) during the iteration on the same loop could lead to potentially unexpected behaviors in PHP < 7. The issue gets even more complicated when the array itself is a reference.

  3. Foreach performance.
    In general, PHP prefers pass-by-value due to the copy-on-write feature. It means that internally PHP will not create duplicate data unless the copy of it needs to be changed. It is debatable whether pass-by-reference in foreach would offer any performance improvement. As is always the case, you need to test your specific scenario and determine which option uses less memory and CPU time. For more information see the SO post linked below by NikiC.

  4. Code readability.
    Creating references in PHP is something that quickly gets out of hand. If you are a novice and don't have full control of what you are doing, it is best to stay away from references. For more information about & operator take a look at this guide: Reference — What does this symbol mean in PHP?
    For those who want to learn more about this part of PHP language: PHP References Explained

A very nice technical explanation by @NikiC of the internal logic of PHP foreach loops:
How does PHP 'foreach' actually work?

Dharman
  • 30,962
  • 25
  • 85
  • 135
  • 4
    Aside from the issues listed, I recommend adding `unset($value);` after the `foreach` closing bracket, to ensure the by-reference variable is no longer available after iteration. https://3v4l.org/2V2AQ – Will B. Jul 09 '20 at 03:04
  • I would suggest to add a comment at the `unset($value);` line emphasizing its importance. This has bitten many PHP developers hard and caused tons of bugs. – rustyx Apr 10 '23 at 12:44
20

Use foreach($fields as &$field){ - so you will work with the original array.

Here is more about passing by reference.

k102
  • 7,861
  • 7
  • 49
  • 69
  • @RBA pls refer to the answers above - they have much more details and updates - I haven't use php for a while now, so unaware of any updates on this – k102 Oct 09 '19 at 16:29
1
function checkForm(& $fields){
    foreach($fields as $field){
        if($field['required'] && strlen($_POST[$field['name']]) <= 0){
            $fields[$field]['value'] = "Some error";
        }
    }
    return $fields;
}

This is what I would Suggest pass by reference

Sagar Kadam
  • 487
  • 1
  • 3
  • 10
  • This Technique is used to change value of original variable. since PHP supports Pass by Value Technique. We need to add the '&' Character in front of variable to state that value to be passed by reference – Sagar Kadam Feb 22 '13 at 12:57
  • 2
    Then why still returning `$fields`? – MAZux Mar 29 '18 at 11:04
  • This is the worst answer of the 3 suggested. For whoever stumbles on this answer, please do not design your functions to change the data in place and return it. For the original author: You have not provided any explanation why this solution would be better than the other ones, or how it works at all.. – Dharman Nov 15 '18 at 13:29
-8

Try this

function checkForm($fields){
        foreach($fields as $field){
            if($field['required'] && strlen($_POST[$field['name']]) <= 0){
                $field['value'] = "Some error";
            }
        }
        return $field;
    }
Nirmal Ram
  • 1,722
  • 4
  • 25
  • 45
  • 5
    Do not do this. I can see at least two things wrong with your code: assigning to $field does not work (the $fields array is never modified when you do this), and return $field returns the singular field, not the array. – Jacob Bruinsma Jun 07 '16 at 17:02