Just today (01/23/2012), reading Habrahabr , the article I was somewhat discouraged. In addition, I noticed that, apparently, experienced programmers here, at HashCode "e also use the following design ( this question ):

foreach($m as &$a) { $a = iconv ('windows-1251', 'utf-8', $a); } 

Firstly, it is not entirely clear why? As far as I remember, the following code in PHP will also be correct:

 foreach($m as $a) { $a = iconv ('windows-1251', 'utf-8', $a); } 

Secondly, from an article on Habré I did not understand how another programmer (for example, Petrovich) could somehow influence the variable &$a , as in our case. Does the effect of this variable really apply to all further code in PHP? Those. scope is not limited to foreach ?

Thirdly, I would not, in such a simple example, especially as a beginner, give such a “subtlety” into service. For as it is said on the same Habré, even the "experienced", to some extent, programmers are confused with this now.

    2 answers 2

    First: Before 5.2 (I can lie) the foreach loop in the as part was doing something like " $a = $m[$i]; ", i.e. created a copy of the variable. After the opportunity to announce the link. / In a function, by the way, it is still not possible in the usual way to pass an indefinite number of reference arguments. /

    Respectively:

     $m = array(1, 1, 1, 1); foreach ($m as $a) $a += 1; // --> $a = $m[$i]; $a++; print_r($m);// 1, 1, 1, 1 foreach ($m as &$a) $a += 1; print_r($m);// 2, 2, 2, 2 

    Further, (secondly) the scope in php is limited only explicitly - by namespaces, methods and functions.

     $m = array(1, 1, 1, 1); $a = 0; function a() { $a++; echo $a; } a(); // notice: undefined... while ($a < 10) echo ++$a; // 1, 2, 3 ... 10 echo $a; // 10 foreach ($m as $b) $c = $b+3; echo $c; // 4 

    Cycles, switches, conditions, and even file nesting do not affect the scope in any way. Perhaps that is why many call templates from a function so that it does not hook up (there is always an $GLOBALS = array).

    Thirdly, the experienced rarely get confused, because the habit of checking and redefining variables is full. And for beginners in php it is generally difficult (it’s easy to read it, it’s hard to understand), because more experience is needed than reason.

    PS: As a result of the Habrovsk case, two noobs are to blame, not links. I see an attempt to accuse the revolver in a shot in the foot.

    ZZY: + secondly, such a case is possible if the scope was not limited at all.

     // file1 $items = array( /* ... */); //file2 foreach ($items as &$item) $item = /* ... */; //file3 foreach ($items as &$item) $item = /* ... */; //file4 require 'file1.php'; require 'file2.php'; require 'file3.php'; 
    • Extremely simple. And in some places it is even logical. Thank. > the foreach loop in part as did something like "$ a = $ m [$ i];" It is strange that he did not do something like $a = &$m[$i]; as in my opinion, it would be more logical. Is not it? - Dex
    • It is here that one can begin to read quotes from the author php) Simply in the entire literature, they either write for for addressing by index or foreach ($m as $n => $a) $m[$n] += 2; , and they write so calmly that the question "is, in fact, what is $a ?" does not occur. Just another crutch that you need to know and take into account in the code. And yes, of course it would be more logical, and the unset variable will be automatic)) But - the wall is stronger than the head) - Sh4dow

    An example on Habré is not very significant. The problem is not in the scope at all and not in the fact that after the loop, $item continues to refer to the last element of the array.

    The main problem is that any transmission by reference affects both operands . If you write $item =& $array[0]; , you affect not only $item , but also $array . This should always be remembered when working with links in PHP.

    I will give a more illustrative example:

     $foo = array(1, 2, 3); foreach($foo as &$item) { $item += 1; } // далее идет 100500 строк кода // мы же помним, что массивы в php передаются по значению? $bar = $foo; // далее $foo и $bar могут "гулять" по коду // передаваться в другие функции и находится в разных namespaces... // ...пока однажды: $bar[2] = 42; // уже догадались, что произошло с $foo? var_dump($foo); 

    T.ch. as a result of the Habrovsk incident, it is the first programmer who is to blame for the unset() after the cycle and thus left behind a minefield that in the future will come around in the wake of the most "mystical" errors.

    • By the way, I don’t want to create a separate question, for the same topic: what to do if you need to assign a value to a variable in which there is already a link? Without unset in particular. $ a = array (1, 1, 1, 1); $ b = & $ a [1]; // how to make $ b become 5, and $ a [1] does not change? and another funny thing: $ varname = 'v'.rand (1, 9999); $$ varname = new stdClass; $ obj = $$ varname; unset ($ varname); // how to destroy an object here? :) - Sh4dow
    • The variable will is_ref flag when the reference count to it is reduced to 1. That is, in this example, you need to do unset($b); and then $b = 5; . No unset can not do. - Ilya Pirogov
    • In the second case, perhaps something like this: foreach ($ GLOBALS as $ k => $ v) {if ($ k! = 'Obj' && $ v === $ obj) {unset ($ GLOBALS [$ k] ); }} unset ($ v, $ obj); - Ilya Pirogov