In reply to Drewseph using foo($a = 'set'); where $a is a reference formal parameter.
$a = 'set' is an expression. Expressions cannot be passed by reference, don't you just hate that, I do. If you turn on error reporting for E_NOTICE, you will be told about it.
Resolution: $a = 'set'; foo($a); this does what you want.
Какво правят референциите
Референциите в PHP позволяват две променливи да сочат към едно и също съдържание. Така че когато правите:
<?php
$a =& $b
?>
Забележка: В случая $a и $b са напълно еднакви - нито $a сочи към $b, нито обратното - просто $a и $b сочат към едно и също място.
Забележка: Ако масив с референции бъде копиран, неговите стойности не се дереференсират (не им се премахва референцията). Това се отнася също и за масиви, предадени по стойност във функции.
Забележка: Ако присвоите, предадете или върнете недефинирана променлива по референция, тя ще бъде създадена.
Example #1 Използване на референции с недефинирани променливи
<?php
function foo(&$var) { }
foo($a); // $a се "създава" и установява в null
$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)
$c = new StdClass;
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)
?>
Същият синтаксис може да бъде използван и с функции, които връщат референции, както и с оператора new (след PHP 4.0.4):
<?php
$bar =& new fooclass();
$foo =& find_var ($bar);
?>
Забележка: Неизползването на оператора & създава копие на обекта. Ако използвате $this в клас, той ще оперира върху текущата инстанция на класа. Присвояването без & ще копира инстанцията (т.е. класа) и $this ще оперира върху копието, което не винаги е желано. Обикновено ще искате да работите с една единствена инстанция с цел бързина и пестене на памет.
Въпреки че можете да използвате оператора @, за да подтиснете каквито и да е грешки в конструктора с @new, това няма да работи, в случай, че се използва израза &new. Това е ограничение в Zend Engine и поради това ще доведе до грешка на синтактичния анализатор (parser error).
Ако присвоите референция на променлива, декларирана като global (глобална) в тялото на функцията, референцията ще бъде видима единствено вътре във функцията. Можете да избегнете това като използвате масива $GLOBALS.
Example #2 Рефериране на глобални променливи в тялото на функция
<?php
$var1 = "Примерна променлива";
$var2 = "";
function global_references($use_globals)
{
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // видима единствено в тялото на функцията
} else {
$GLOBALS["var2"] =& $var1; // видима също и в глобален контекст
}
}
global_references(false);
echo "var2 е установена в '$var2'\n"; // var2 е установена в ''
global_references(true);
echo "var2 е установена в '$var2'\n"; // var2 е установена в 'Примерна променлива'
?>
Забележка: Ако присвоявате стойност на променлива чрез референции в конструкцията foreach, референциите се променят също.
Example #3 Референции и конструкцията foreach
<?php
$ref = 0;
$row =& $ref;
foreach (array(1, 2, 3) as $row) {
// прави нещо
}
echo $ref; // 3 - последния елемент от итерирания масив
?>
Второто нещо, което правят референциите, е да предават променливи по референция. Това става чрез насочването на локалната променлива във функцията и променливата в извикващия обхват към едно и също съдържание. Пример:
<?php
function foo (&$var)
{
$var++;
}
$a=5;
foo ($a);
?>
Третото нещо, което референцията прави е връщане по референция.
Какво правят референциите
09-Jun-2008 09:33
30-May-2008 02:15
If you set a variable before passing it to a function that takes a variable as a reference, it is much harder (if not impossible) to edit the variable within the function.
Example:
<?php
function foo(&$bar) {
$bar = "hello\n";
}
foo($unset);
echo($unset);
foo($set = "set\n");
echo($set);
?>
Output:
hello
set
It baffles me, but there you have it.
01-Apr-2008 09:56
The order in which you reference your variables matters.
<?php
$a1 = "One";
$a2 = "Two";
$b1 = "Three";
$b2 = "Four";
$b1 =& $a1;
$a2 =& $b2;
echo $a1; //Echoes "One"
echo $b1; //Echoes "One"
echo $a2; //Echoes "Four"
echo $b2; //Echoes "Four"
?>
19-Oct-2007 01:59
points to post below me.
When you're doing the references with loops, you need to unset($var).
for example
<?php
foreach($var as &$value)
{
...
}
unset($value);
?>
09-Oct-2007 12:25
Watch out for this:
foreach ($somearray as &$i) {
// update some $i...
}
...
foreach ($somearray as $i) {
// last element of $somearray is mysteriously overwritten!
}
Problem is $i contians reference to last element of $somearray after the first foreach, and the second foreach happily assigns to it!
06-Jul-2007 10:50
Solution to post "php at hood dot id dot au 04-Mar-2007 10:56":
<?php
$a1 = array('a'=>'a');
$a2 = array('a'=>'b');
foreach ($a1 as $k=>&$v)
$v = 'x';
echo $a1['a']; // will echo x
unset($GLOBALS['v']);
foreach ($a2 as $k=>$v)
{}
echo $a1['a']; // will echo x
?>
08-Jun-2007 08:59
Something that might not be obvious on the first look:
If you want to cycle through an array with references, you must not use a simple value assigning foreach control structure. You have to use an extended key-value assigning foreach or a for control structure.
A simple value assigning foreach control structure produces a copy of an object or value. The following code
$v1=0;
$arrV=array(&$v1,&$v1);
foreach ($arrV as $v)
{
$v1++;
echo $v."\n";
}
yields
0
1
which means $v in foreach is not a reference to $v1 but a copy of the object the actual element in the array was referencing to.
The codes
$v1=0;
$arrV=array(&$v1,&$v1);
foreach ($arrV as $k=>$v)
{
$v1++;
echo $arrV[$k]."\n";
}
and
$v1=0;
$arrV=array(&$v1,&$v1);
$c=count($arrV);
for ($i=0; $i<$c;$i++)
{
$v1++;
echo $arrV[$i]."\n";
}
both yield
1
2
and therefor cycle through the original objects (both $v1), which is, in terms of our aim, what we have been looking for.
(tested with php 4.1.3)
03-Apr-2007 05:11
Here's a good little example of referencing. It was the best way for me to understand, hopefully it can help others.
$b = 2;
$a =& $b;
$c = $a;
echo $c;
// Then... $c = 2
05-Mar-2007 08:56
I discovered something today using references in a foreach
<?php
$a1 = array('a'=>'a');
$a2 = array('a'=>'b');
foreach ($a1 as $k=>&$v)
$v = 'x';
echo $a1['a']; // will echo x
foreach ($a2 as $k=>$v)
{}
echo $a1['a']; // will echo b (!)
?>
After reading the manual this looks like it is meant to happen. But it confused me for a few days!
(The solution I used was to turn the second foreach into a reference too)
17-Apr-2005 12:05
I ran into something when using an expanded version of the example of pbaltz at NO_SPAM dot cs dot NO_SPAM dot wisc dot edu below.
This could be somewhat confusing although it is perfectly clear if you have read the manual carfully. It makes the fact that references always point to the content of a variable perfectly clear (at least to me).
<?php
$a = 1;
$c = 2;
$b =& $a; // $b points to 1
$a =& $c; // $a points now to 2, but $b still to 1;
echo $a, " ", $b;
// Output: 2 1
?>
16-Nov-2004 01:16
In reply to lars at riisgaardribe dot dk,
When a variable is copied, a reference is used internally until the copy is modified. Therefore you shouldn't use references at all in your situation as it doesn't save any memory usage and increases the chance of logic bugs, as you discoved.
11-Apr-2003 01:46
So to make a by-reference setter function, you need to specify reference semantics _both_ in the parameter list _and_ the assignment, like this:
class foo{
var $bar;
function setBar(&$newBar){
$this->bar =& newBar;
}
}
Forget any of the two '&'s, and $foo->bar will end up being a copy after the call to setBar.
