Foreach by reference or by value?

Asked

Viewed 1,005 times

8

Is there a difference in performance and safety between using foreach by reference or by value? I always use the first option(when necessary) by finding the code less confusing to read.

Reference:

Here I trade all values of an array for the string exemplo using reference passage.

foreach ($array as $key => &$value) {
    $value = 'exemplo';
}

Valor:

Here I trade all values of an array for the string exemplo using pass by value.

foreach ($array as $key => $value) {
    $array[$key]= 'exemplo';
}

Example:

Here is an example of a code of mine (with a few lines removed to make it easier to understand) in which I do what some answers and comments say would go wrong, but I have no mistake:

foreach ($array as $key => &$value) {
    //Removida as linhas em que calculo alguns valores para a substr.
    $value['arq_descricao'] = substr($value['pes_texto'], $inicio, $tamanho);
}
  • 2

    Related: http://answall.com/questions/80815/behavior-do-foreach-com-vari%C3%A1veis-by-refer%C3%Aancia

  • As much as the two questions are about foreach, I don’t think they’re alike.

  • 1

    "Related" is not "duplicated". At no time said they were similar. Your question received votes for closure because it takes the response based on opinions.

  • @Sorry wallacemaxters, I’m new to the site

  • 1

    My linked question is already a point for you to avoid using by reference, or, if using, use carefully.

  • No problem, William. You can edit your question to stay within the scope and be accepted. I think the question itself aborts a very interesting topic, but the problem was the final question. She asked for an opinion. I think wanting to know the issue of safety and performance is not bad, but the issue of readability is already very personal.

  • The guy’s asking about performance and best practices, this link there has nothing to do.

  • If you don’t mind, I can edit the last snippet so she stays within the scope...

  • 1

    @Pedromorais is a point for him to avoid use, as I said before. And to tell you the truth, his answer is that he didn’t answer anything. I commented below the negative reason to show that the answers need to be improved.

  • 1

    @Wallacemaxters But I asked the opinion because I want to know the same personal answer, it’s like asking if in your opinion is worth using if without keys. One of the answers would surely be related to good practices and would say to always use keys in the if.

  • "Good practice" is very relative. This is the problem. What is good for me, can be bad for you, you understand... So I’m going to try to give you as impartial an answer as possible.

  • @Guilhermepressutto I will give a +1, because although it leads to opinions, I believe that some aspects of the questions are interesting to lead to an answer not based on opinions, but that clarifies about the differences between one and the other.

Show 7 more comments

3 answers

3


Performance

I’m not an expert on the subject, but I can assure you that the performance in this case doesn’t make so much of a difference that it’s worth choosing one or the other because of it.

Safety - Understanding each other’s behavior

The only safety that is at risk is yours. I say this because it is necessary to understand the behavior of references in this case.

How it was answered in this question there is a small variation from what is expected of a normal foreach in relation to the variable passed by reference.

In short: The last value is always referenced, it can cause you problems if you overwrite the value of $value.

$array = [1, 2, 3];

foreach ($array as $key => &$value) {
    $value = $value . 'R$';
}

$value = null;

That would generate:

['1R$', '2R$', null]

See an example on IDEONE

So after using a foreach with reference, it is always good to call unset on the referenced variable (after the loop).

I won’t talk about it much here, because the linked question has enough on the subject.

In this case, I’m not telling you not to do it like this (I’ve done it a few times). I’m just warning you that you better know everything about it, so that "you don’t know" causes you problems.

But, noting that may arise a "new behavior" in relation to the first foreach - and at the same time, it can also affect readability if you forget to treat the reference variable properly-, I could think of your second option as being the best.

$array = [1, 2, 3];

foreach ($array as $key => $value) {
    $array[$key] = $value . 'R$';
}

But it is necessary to know if it is necessary and if it is wise to change the original value of your array. If you’re sure you won’t be using the array ""original, so you can do it without fear of being happy :p

The reference disadvantage with foreach

Remembering that also you have a disadvantage when using foreach with reference: You can only loop with the array stored in variables. Arbitrary expressions cannot be used with reference in some versions of PHP prior to 5.5.

Example:

// Certo:

$array = [];

foreach ([1, 2, 3, 4] as $key => $value) {
    $array[$key] = $value . 'R$';
}

// Errado: Isso vai gerar um erro caso use PHP 5.4

foreach ([1, 2, 3, 4] as $key => &$value) {
    $value = $value . 'R$';
}

See a small test

Draw your own conclusion

I don’t want to give you an opinion on the subject, I just want you to understand that do a foreach with reference and do a reallocation with the keys of the foreach may seem like the same thing, but technically it’s not. References can be villainous if not used wisely. Similarly overwrite a value of a array might not be a good idea if you want to keep the original values.

I’m showing you some points, because this "good practice" thing is actually pretty personal. Always better you know what you’re doing and know how to use it at the right time.

  • 1

    Why does this error happen in your code but not in my code? I will edit the question with the code in question.

  • Has the error_reporting activated?

  • @Guilhermepressutto will edit the question. Really, it depends on the PHP version.

  • Look at the "Example" part. I basically do what your answer and linked question say would go wrong, but not wrong.

  • @Guilhermepressutto I saw here, tested on http://sandbox.onlinephpfunctions.com/. The error only occurs with PHP version 5.4. I’ll see if the documentation says anything about it, I don’t remember seeing it as "new features" when PHP 5.5 was released.

  • Actually here in the company I work with PHP 5.3.3-7.

Show 2 more comments

-1

If you really need the key($key) you use the second option, because sometimes I need to change the value of the variable, for example:

$ar = ['a'=>'x','b'=>'y'];
    foreach($ar as $key => $value){
        $ar[$key] = $value+'alterado';
}

Now if you’re not going to change the value of the parent array ($ar), or use $key, the performance and reading are better (changes almost nothing, but are better)

  • 4

    -1 This does not answer the question. Could you add any explanation to the answer?

  • You had at least the trouble of reading the whole answer ?

  • In your case I would use foreach($ar as $key => &$value){ $value = $value.'alterado'; }

  • 4

    Has only code...

  • look at the commented part

  • @Pedromorais I edited the answer...

  • Thanks, I’m having trouble mixing code and text in the answers

  • 2

    Okay. Well, I think it looks better, but still the explanation is a little vague. For example: "performance and reading are better"... Based on what? Do you ever test? If you did, please add the answer. If it’s any source, please add the source link.

  • 1

    I think this discussion can now be closed. He replied that it is only worth using this code of his when there is no way to use another and I have already commented that can use otherwise yes.

Show 4 more comments

-1

When you work with value you have a new instance of the array. When you work with reference, you modify the original array.

Basically, when you use the array by value you have a copy of that valid array only within the scope of foreach, for, while and the like.

Run the example below to get an idea.

<?php

$array = ['a','b','c','d','e'];

echo "Array original";
echo "<pre>";
print_r($array);
echo "</pre>";

foreach($array as $k => $v) {
    $v = $k;
}

echo "Array após foreach por valor";
echo "<pre>";
print_r($array);
echo "</pre>";

foreach($array as $k => &$v) {
    $v = $k;
}

echo "Array após foreach por referência";
echo "<pre>";
print_r($array);
echo "</pre>";
  • 2

    "When you work with reference you have a new instance of the array, in the array case. " could you explain this? When you use reference, you are working upon the original value of array. And I think you forgot the symbol & before the variable $v.

  • In the example, using by reference, the original array remains unchanged. You make valid changes only in the scope of that repetition structure.

  • 1

    You’re not using the reference. You’re doing a foreach where the copy normally takes place. What you were asking was something else. Observe the code of the first example of the question and you will see that it put the & (reference signal) there.

  • After correcting the inversion, I also made a small change in the code. I believe that now everything is correct.

  • 1

    I’m trying to figure out how that answers the question. He asked about performance, readability and security, but this was not mentioned in the answer...

  • 1

    Your answer is my question, a little less complete. I already said that you answered my question, and I even put how to change the original value even when passing by value.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.