Variable Reference

2

I'm studying PHP and I came across a question of variables by reference and I did not quite understand how it behaves.

function foo(&$var) {
   $var++;  
}
$a=5;
foo($a);
echo $a; // Retorna 6

When I saw this function I thought, "Yeah, but if I make a normal call with return $var++ it will also work ...

function bar($var) {
   return $var++;
}
$b=5;
bar($b);
echo $b; // Retorna 5

I could not understand very well the behavior and why the first function does the increment and the second function does not.

    
asked by anonymous 14.01.2016 / 13:21

4 answers

6

Simplifying

In this first case, the following happens:

function bar($var) {
   $var++;
   return $var;
}
$b = 5;
echo bar( $b ); // Mostra 6 - valor do return
echo $b;        // Mostra 5 - valor do $b
  • is 5 a $b .
  • You call the bar function, passing the value 5 to it.
  • value 5 is stored in $var , which is incremented.
  • You echo in $b , which never stopped being 5 .

See the difference. I used the same variables as the previous case to simplify:

function bar( &$var ) {
   $var++;
   return $var;
}
$b = 5;
echo bar( $b ); // Mostra 6 - valor do return
echo $b;        // Mostra 6 - valor do $b
  • is 5 a $ b.
  • You call the bar function, passing the $b variable to it. (this happens thanks to & , which caught the reference and not the value ).
  • $b is same as than $var , and incremented.
  • echo echo in $b , which has been incremented within bar
    (via its "alias name" $var , which has become the name of $b in the function).

In summary, in the first case, $var is created inside the function with value 5. In the second case, $var is $b with a new name.


Complicating

I changed the examples above to use the same variables, and I put the increment on a separate line, so as not to fall into this mess:

function bar( &$var ) {
   return $var++;
}

$b = 5;
echo bar( $b ); // Mostra 5 - valor do return
echo $b;        // Mostra 6 - valor do $b

Notice something strange? That's right, check out IDEONE .

The strange result in the first echo has nothing to do with being by reference or not, but with the fact that we are incrementing $var AFTER return. If it were ++$var , the two lines would show 6.

Although not part of the question, I thought it better to comment because if the function of the question was tested with echo in return, it could disrupt the understanding.

At a glance: In this case, we pass $b to the function. In the function we return $var , which is the $b out of the function, that is, 5 . After return is applied ++ , which incremented $b (called $var within function).

    
14.01.2016 / 13:33
3

Functions where parameters have a & means that you must pass a variable with a simple value does not work. Passing by reference means that the passed variable will have its value changed by the function, if it is destroyed within the function and you make some action on it after execution, an error will be generated.

function foo(&$var) {
   $var++;  
}
foo(5);//erro.

Passing argument by value means that variable or passed value will be copied to function and its 'original' will remain unmodified.

Example 1

function porReferencia(&$arg){
    $arg = 'modificado por referência';
}

$argOriginal = 'original';
referencia($argOriginal);
echo $argOriginal; //modificado por referência

Example 2

function porValor($arg){
    $arg = 'modificado por valor';
    return $arg;
}

$arg = 'original';
porValor($arg);
echo $arg; //original

With some exceptions, a function should only modify the values passed as argument (copy) and its internal variables and not variables outside its scope (global), the changes must be returned, in this way the original content is not lost if it is necessary to use it or compare it as in example 2

In other languages it is possible to set up an interesting example where you pass a variable or object to a function / method and inside it destroys the reference, after the call tries to access that variable and a general error saying that the identify never existed. / p>     

14.01.2016 / 13:33
3

The passage for reference I believe to be one of the coolest things in programming.
I think one of the questions to ask when studying this is:

  • Reference for what?

Memory

Imagine that when you are programming and assigning a variable: $var = 5; , you are not simply assigning 5 to a $var variable, you are reserving a location in the memory of your computer that will have as alias the name $var and it local will have the value 5.

 0050 | 0051 | 0052 | 0053 | 0054 | 0055 | 0056     <-- possição da memoria
      |      | $var |      |      |      |          <-- alias
      |      |   5  |      |      |      |          <-- valor/referencia

The alias is actually just an access to the contents of 0052 of memory.

When you generate a passage by reference you are saying that the content of that memory is not a value, but a reference to a location that has the value. It's kind of complicated, but it's basically like this:

$b = &$var;

 0050 | 0051 | 0052 | 0053 | 0054 | 0055 | 0056     <-- possição da memoria
      |      | $var |      |  $b  |      |          <-- alias
      |      |   5  |      | 0052 |      |          <-- valor/referencia

Now when you access $b eĺe it will not display 0052 because it is a reference, it goes to the reference and gets its value in the 5 case.

In this way if the content of the 0052 setting is changed both $var and $b will be changed changed. Remember that you can change it both by $var and $b .

$var = 7;

 0050 | 0051 | 0052 | 0053 | 0054 | 0055 | 0056     <-- possição da memoria
      |      | $var |      |  $b  |      |          <-- alias
      |      |   7  |      | 0052 |      |          <-- valor/referencia

$b = 10;

 0050 | 0051 | 0052 | 0053 | 0054 | 0055 | 0056     <-- possição da memoria
      |      | $var |      |  $b  |      |          <-- alias
      |      |  10  |      | 0052 |      |          <-- valor/referencia

Function

When you generate a function, the variables you create as a parameter generate an in memory, if they are not of the reference type, they wait to receive a value, if are of the reference type get the reference of the passed variable.

function teste($a){

}

 0080 | 0081 | 0082 | 0083 | 0084 | 0085 | 0086     <-- possição da memoria
      |      | $a   |      |      |      |          <-- alias
      |      |      |      |      |      |          <-- valor/referencia

teste($var);

 0080 | 0081 | 0082 | 0083 | 0084 | 0085 | 0086     <-- possição da memoria
      |      |  $a  |      |      |      |          <-- alias
      |      |   5  |      |      |      |          <-- valor/referencia


function teste(&$a){

}

 0080 | 0081 | 0082 | 0083 | 0084 | 0085 | 0086     <-- possição da memoria
      |      | $a   |      |      |      |          <-- alias
      |      |      |      |      |      |          <-- valor/referencia

teste($var);

 0080 | 0081 | 0082 | 0083 | 0084 | 0085 | 0086     <-- possição da memoria
      |      |  $a  |      |      |      |          <-- alias
      |      | 0052 |      |      |      |          <-- valor/referencia

Thus $a within the function changes the location of memory 0052 , changing the content definitively.

    
14.01.2016 / 16:55
1

It took me years to understand why I have always avoided using and also for not understanding the practical use in real situations. And also for not having had an interest.

I've always seen examples with parameters in function foo(&$var) { functions but I did not understand why I use this because I can do using global or static property of a class.

A few years ago I saw a very different and simple example using array. This aroused interest in understanding the use of this parameter feature by reference.

The array example I saw was something like this:

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

    print_r($arr);

    /*
Array
(
    [0] => a
    [1] => b
    [2] => c
)

    */

    $foo = &$arr[0];
    $foo = 'a modified';

    print_r($arr);

    /*
Array
(
    [0] => a modified
    [1] => b
    [2] => c
)

    */

See how $foo acts as a reference, ie as a shortcut (alias) of the array you received in your declaration.

Anything that $foo receives, will be "mirrored" directly in $arr[0] .

This makes it much easier to manipulate multidimensional arrays.

There are several other uses, as quoted in the other answers.

When thinking about assignments by reference, always imagine a fake variable where the value is merely a link in the memory address, that is, an alias.

    
14.01.2016 / 17:48