Can reference arguments be harmful?

Asked

Viewed 397 times

7

By default, arguments of a function are passed by the value (i.e., if the value of the parameter within the function is changed, it is not changed outside the function). To allow a function to modify its arguments, they must be passed by reference.

To have an argument for a function always passed by reference, we add a E commercial (&) for the argument desired in the function function, as in the example:

<?php
function something(&$string)
{
    $string .= 'B';
}

$variavel = 'A';

something($variavel );
echo $variavel;//Irá mostrar "AB"

I rarely use references in PHP function arguments (not to say never), as I’ve never really seen need or advantage.

But I remembered that I read once that the use of reference is not "good" (I do not remember where I read), but I notice that sometimes it is used, I wonder if the use of references in arguments implies some problem or loss of performance?

3 answers

6


Harmful, I would say yes

Currently I would say yes, can be harmful given the form as the whole process unfolds since version 5.3.0.

As of version 5.3.0, if the function call has the &, a Warning with:

call-time pass-by-Ference

As of version 5.4.0, the above error has been removed, and we get the fatal error.

This means that we can no longer signal in the code, in the call of a function, that a certain value is being passed as a reference, and the reading of the code is being difficult. To know, we need to access "physically" the function and observe the arguments of it.

Harmful no doubt because the control is now restricted, giving rise to a greater probability of errors and/ or mistakes by the programmer, in particular in projects where several are involved.

Perks

The only advantage I ever saw in passing values by reference was the fact that we had a fallback in case something goes wrong way down in the code.

Or the reverse, having control variables that are being manipulated within functions "more within" our code, without having to walk with them back and forth, with return everywhere:

$super = 1;

function umControloQualquer(&$super) {

    (int)((int)true==1)+2 ? $super++ : $super=0;
}

umControloQualquer($super);

// 5000 linhas e 20 ficheiros depois...

if ($super>=2)
    echo $super;
else
    echo "Alguma coisa correu mal porque o BuBu deveria ser nível II neste momento!";

Control variable simulation passed by reference to a function that will change the same depending on a check. The example is simplicist, but mirrors a practical case.

See on the Ideone.

  • Good Zuul, I think I understand the use "wrong" is not in function foo(&$a){} is in the echo foo(&a); for example, i.e. function foo(&$a) will not issue error, but echo echo foo(&$a) go, correct me if I’m wrong. Grateful :) +1, can I release an issue? To make this clearer :)

5

If the resource exists it is because there is a reason for its use. Unless there is something complementary that makes it obsolete.

Probably the recommendation not to use is to try optimizations. This can be considered premature optimization, mainly because PHP already does optimization of passing the argument by reference when this is useful even if it has no mention to pass by reference. Of course, if the expected semantics is not the passage by reference, the optimization is about using the technique of copy-on-write. So an attempt to optimize by passing something by reference can even hinder this optimization.

Nor will I repeat what I always say that micro-optimizing PHP is not usually the most productive thing.

Although rare, there may be the problem of starting to have references p/references and losing control if it is used in exaggeration.

But if the intention is really to go through reference, if you have a good reason to use it, then that’s okay. And in fact, it’s rarely necessary. Almost always when someone thinks of using a reference, they are probably thinking about the performance or did not find a better way to do the same, so the use is wrong.

Almost whenever the intention is to pass by reference, it should do so with a type that is naturally passed with this semantics.

But for everything there is reason to use or not to use. Like everything, use if really know what you’re doing, if you understand all the implications. And don’t use it if you don’t know why you’re using it. Not everyone understands what happens to data when you use a reference. It is not so complicated, but it is easy to forget that you are manipulating a reference and this has consequences on all writing performed in that variable.


I understood the use of reference in argument that is different from parameter. But after Zuul’s reply I paid more attention to the example and saw something different.

You do have a problem.

It is one thing to say that you want to pass an argument by reference, according to the title of the question, it is quite another to ask in the parameter that the argument be received by reference implicitly. That is, who calls does not know that is passing by reference something that should be passed by value in normal conditions.

But what kind of language does that allow? PHP, of course. And the language maintainers have outdone themselves. I didn’t know but newer versions made the problem even worse.

Forcing the caller to use a reference is not so bad. Think about it. If the caller is explicitly by way of reference, it shows that it knows that this semantics is being used, what harm can it cause? At most, what I quoted, the programmer did not know right what this means.

Then a possibility of language improvement would be to force the call to use the reference in the argument when the parameter was annotated to be received by reference.

But what did she do? Forbade to do :D This... is... in-believable!

Then the new versions made the reference impractical for those who like organized code, expressive, code that indicates their intention and does not give room to misinterpretation. As the reference passage is now required to be implicit use it if you want to create confusion.

That would be the "right":

<?php
function something(&$string) {
    $string .= 'B';
}
$variavel = 'A';
something(&$variavel); //<============ Note aqui
echo $variavel; //Irá mostrar "AB"

But this does not compile. What was certain was that this was mandatory. So the "signature" of the call matches the signature of the function definition. That is, both have the reference.

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

I’m not saying that careful programmers can’t program using implicit references without causing problems. But careful programmers code in C, in Assembly :) What I mean is that PHP should not be a language where you have to have this kind of concern. Actually this specifically, nor does C. In C you have to be explicit.

Of course I’m not talking about the types that are known to be by reference, so how is it known to every programmer is easier to understand.

In conclusion, there is a problem of readability, yes, but that does not mean that it should not be used under any circumstances. I would really avoid it and when I needed to use it, I would document it ostensibly.

  • Thank you, as always with a great response, just did not understand the need for comment If there is a resource it is because there is a reason for its use., in no time did I inquire why of him exist.

  • 2

    Of course, it is because I like to put a more complete information so that everyone understands. It was an introduction to reach the conclusion of the last paragraph. In a way I question who says it is not to use, in general these rules generate more confusion that help because they do not explain. In your case you question and do not claim, but you should already know that the answers are better when they answer to everyone and not only to those who asked. I started wanting to break the myth, because I also read people saying p/ñ use and point.

  • I understood, I agree, it was really quite common (today I don’t see this anymore), maybe it was something of confusion even on their part (famous gossip). + 1, for now I will wait, if I have no more complete answer then I will mark yours. Grateful

  • I updated because I stuck to the question title but looking at the whole, what Zuul wrote makes more sense. I was confused because of the terminology. Few languages let the reference be implicit when the parameter should be by value, but PHP overcame prohibiting being explicit.

  • If I understand the situation is just in calling echo foo(&$a) and not in the declaration function foo(&$a), ie the code I quoted has no problem "any" (not that it is really something useful), so the restriction only if at the time of use. Perhaps providing an example for people not to get confused would be interesting, after all "caller" is not always clear.

  • It depends on what you call "Problem". Looking around, you see what’s happening. But think that you do not have access to the easy function so. You call something($variavel);, you hope that $variável that has value semantics be changed inside? Remember, without seeing the function? Don’t you think it’s a problem not to be clear that it will be changed? It is not a big problem, but it is a small problem. But if you expect it to happen in this function, you are well informed of it, it is no problem. It is not the reference that is problem, it is implicit.

  • The problem of providing an example that would be more correct is that it no longer works in recent versions of PHP :) PHP did this nonsense, now we can not use the way "right".

  • The function is merely illustrative, the example would be to understand what "prohibited" in PHP in the new versions, use in the case declarar função=Ok, use in the tempo chamada=Proibido, because sometimes examples become clearer to understand the different situations.

  • 1

    PHP has never done it the way you say it’s right, @bigown. Even 5.2 it allowed you to pass anything by reference even if the function’s signature didn’t say that. Then you had the reverse problem: the functions generated side effects without intending to do it.

  • 1

    @bfavaretto yes, I know. But at least in that sense that I’m talking about, you explicitly say that going through reference is not so serious, although potentially problematic as well. At least it’s explicit. Bad not to be explicit. Sure, you can be a nerd if you pass as a reference something you shouldn’t, but at least you know what you’re getting yourself into. The ideal, of course, is for the signatures to match as I put it in the last issue.

  • @bfavaretto your comment would be worth an answer, so simple but enlightening, the side effects you quoted is the reason for everything :)

Show 6 more comments

2

This answer is only complementary;

In short

The rumours on the use of references &$variavel referred to only when you call the functions and not when you declare them, i.e.:

This is permitted and valid (in addition to useful):

function foo(&$a) {
   $a = 'b';
   return true;
}

This is no longer allowed and issues errors since php5.3:

$a = 'a';
var_dump(foo(&$a));

The problem

The "problem" of using reference nay refers to the use in statement functions, such as:

function foo(&$a) {
   $a = array();
}

$test = array();
foo($test);
print_r($test);

But yes when calling a function and using the reference, such as:

...
foo(&$test);//Chamando a função
print_r($test);

That is, from the moment of the call (call-time pass-by-Ference), in other words, at the time of the declaration "no" there is problem.

When to use

As already mentioned, the use of references in arguments of functions are not so useful, however a situation that can be made useful would be similar to the function bool exec($comando, $saida);, for example:

function foo($a, &$b) {
    $b = array();
    if ($a === 'A') {
        return true;
    }

    return false;
}

Many native PHP functions make use of this, such as: rsort, sort, exec, array_walk, preg_match_all, etc..

Another situation we can use is the use of the function array_walk, for example:

function foo(&$item, $key){//Usando referencia em item
   if($key === 'c'){
        $item = 'Tchau';
   }
}

$arr = array('a' => '1', 'b' => '2', 'c' => 'Oi');

array_walk($arr, 'foo');
print_r($arr);

The way out will be something like:

array(
    [a] => '1',
    [b] => '2',
    [c] => 'Tchau'
)

We’re obligated to use this?

When creating/declaring a function we don’t need it (unless you want to), you can use other ways to return the value, such as a simple return ...;. If you want to return two different data we can use an associative array as for example:

function foo($a) {
   ...
   return array(
       'status' => $x, //Retorna boolean
       'message' => $y //Retorna string
   );
}

Browser other questions tagged

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