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 は同じ場所を指しているのです。
注意: リファレンスを含む配列をコピーする際に、そのリファレンスが解消される ことはありません。配列を関数に値渡しする場合も同様です。
注意: 未定義の変数のリファレンスに対して代入したり 渡したり返したりすると、そこで変数が作成されます。
例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 の仕様により、これはパースエラーとなります。
関数の内部で global 宣言された変数にリファレンスを 代入すると、そのリファレンスは関数の内部でのみ参照可能となります。 これを避けるには、$GLOBALS 配列を使用します。
例2 関数内でのグローバル変数の参照
<?php
$var1 = "Example variable";
$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 の値は 'Example variable'
?>
注意: foreach ステートメント の内部でリファレンス変数に値を代入すると、リファレンスも変更されます。
例3 リファレンスと foreach ステートメント
<?php
$ref = 0;
$row =& $ref;
foreach (array(1, 2, 3) as $row) {
// 何かを実行します
}
echo $ref; // 3 - 配列の最後の要素
?>
リファレンスの第 2 の使用法は、変数のリファレンス渡しです。この場合、 関数でローカル変数が作成され、コール側の変数が、それと同じ内容への リファレンスとなります。例を示します。
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
?>
リファレンスの第 3 の使用法は、 リファレンスによる返り値 です。
リファレンスが行うことは何ですか?
10-Jun-2008 03:33
30-May-2008 08: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 03: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 07: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 06: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 04: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
?>
09-Jun-2007 02: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 11: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 03: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 06: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 08: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 07: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.
