PHP: Vysv�tlen� referenc� (odkaz�) - Manual
PHP  
downloads | documentation | faq | getting help | mailing lists | | php.net sites | links | my php.net 
search for in the  
<Comparing objects in PHP 5Co reference d�laj�>
view the version of this page
Last updated: Fri, 18 Apr 2003

Kapitola 15. Vysv�tlen� referenc� (odkaz�)

Co jsou reference

Reference (odkazy) jsou prost�edek, jak v PHP p�istupovat k t�mu� obsahu prom�nn� pod r�zn�mi jm�ny. Nejsou to ukazatele (pointery) jako v C, jsou to aliasy v tabulce symbol�. Uv�domte si, �e v PHP je rozd�l mezi n�zvem prom�nn� a jej�m obsahem, tak�e stejn� obsah m��e m�t r�zn� n�zvy. Nejbli��� analogi� jsou n�zvy soubor� a soubory v UNIXu - n�zvy prom�nn�ch jsou polo�ky adres��e, obsahy prom�nn�ch samotn� soubory. Na reference m��e b�t naz�r�no jako na hardlinky v UNIXov�m syst�mu soubor�.



User Contributed Notes
Vysv�tlen� referenc� (odkaz�)
add a note
20-Dec-2001 05:46
Succesive assignement by reference and simple assignement :

$a = 'old';
$b = &$a;
$a = 'new';// now $b's value is new
$c = $b;// simple copy
$a = 'new new'; // $b is 'new new', $c is still 'new'

And now with arrays :
$a[0] = 'old';
$b = &$a;
$c = $b;//simple copy
$a[0] = 'new';// $b[0] is new, and $c[0] is still 'old'

BUT :

$a = 'old';
$b[0] = &$a;
$c = $b; // simple copy
$a = 'new';//now BOTH $b[0] and $c[0] are 'new'

A simple copying of an array (or an object) does NOT
break references for the values (or instance variables).
Use var_dump() to see which of the values in an array
are references.

Ivan

ken at nospam dot notenetwork dot com
11-Jan-2002 02:44

You may be looking for how to iterate over an array by reference. For example, you have an array of objects, and you want to call methods that modify the objects. A normal foreach doesn't work, as the elements of the array are copied. each() doesn't work either. You have to use a for loop.

Example of what *COPIES* objects (not what you probably want):

foreach($object_list as $object) {
$object->method();
}

Example of what does not copy objects (probably what you want):

for ($c = 0; $c = count($object_list); $c++) {
 $object = &$object_list[$c];
$object->method();
}

You get the picture.

shepnorfleet at comcast dot com
17-Jan-2002 05:55

Caveat, if your using an associative array with the key pointing to a reference your going to want to do somehting like this:

reset($MyArray);
while($Key = key($MyArray))
{
  $_MyRef = & $MyArray[$Key];
  ...Do Smothing...
  next($MyArray);
}

cody at iensemble d0t c0m
07-Mar-2002 06:26

Another way to iterate over an array of references:

foreach (array_keys($myArray) as $key) {
  doSomething($myArray[$key]);
}

This works on "normal" and associative arrays.

vincent at sunlight dot tmfweb dot NO_SPAM dot nl
27-Mar-2002 11:37

For the Java programmers among you, there's a big difference between Java and PHP. In Java, all objects are passed by value (as in PHP). However, try this in PHP:

class Object {
var $value;
function Object() {
$this->value = 5;
}
function getValue() {
return $this->value;
}
function setValue($value) {
$this->value = $value;
}
}

function updateObject($object) {
$object->setValue($object->getValue() + 5);
echo ', ', $object->getValue();
}

$object = new Object();
echo $object->getValue();
updateObject($object);
echo ', ', $object->getValue();

It prints: '5, 10, 5'.

If you implement this same code in Java however, it will print '5, 10, 10'!

Explanation: 'passing by value' in Java means that assigning a different value to a variable inside a function will not change it outside a function. (PHP equivalent: '$object = new Object'.) But calling methods on the variable (when it's an object) can change the object (In PHP: '$object->setValue(9)'). With PHP the latter isn't true, unfortunately.

If you use objects in PHP, you have to use references almost all the time, even if you don't want to assign a new value to an outside variable, but just want to call methods (that might update the object).

henrik dot gebauer at web dot de
02-Apr-2002 08:34

If you want to check whether there is a reference between two variables you can use this function.

function check_reference(&$var1, &$var2)
{
   // Save old values
   $var1_old = $var1;
  $var2_old = $var2;
   
   // ($var1 . ".") must not be $var2
   if($var1 . "." == $var2)
       $var1 .= ".";

   // Change $var1
   $var1 .= ".";
   
   // Did $var2 also change?
   if($var2 == $var1)
       $reference = true;
   else
       $reference = false;

   // Old values
   $var1 = $var1_old;
   $var2 = $var2_old;
   
   return $reference;
}

info at paralight dot ru
08-Apr-2002 10:34

A have found interesting strange in references to classes.

class Child{
function Child(&$parent)
{
$this->parent=&$parent;
$this->parent->var=10;
}
function doit()
{
$this->parent->var=20;
}
}

class A{
function A()
{
$this->child=new Child($this);
}
function doit()
{
$this->child->doit();
echo $this->var;
}
}

$a = new A;
$a->doit();

-----------------
In result we have 10, not 20.

And, if we call $a->doit(); from constructor �():
function A()
{
$this->child=new Child($this);
$this->doit();
}
we resulting 20.

The way to takearound this is make empty constructor, move all from it to function constr(), and run some like:

$a=new A;
$a->me=&$a;
$a->constr();
$a->doit();

in constr() we have $this->child=new Child($this->me); [not Child($this)].

and, as result we have 20 as would be expected.

That's this? Am I missunderstand something or it is PHP bug?

23-Apr-2002 01:07
When you do

   $a = new A();

PHP creates an object for you, and returns a COPY of that object
So (if I get it right... ) the child is actually altering the original object and not the copy that you stored in $a.

However if you do

   $a =& new A();

PHP still creates an object, but returns a REFERENCE to that object.
The child is still altering the original - but you are happy, because you have got a reference the original!

so if you change the line

  $a = new A();

to

   $a =& new A();

you'll get the result you expected.

(BTW wouldn't it be more correct to say that when you do:

   $a = new A()

PHP returns not a copy but a reference to a copy?)

vic at NO_SPAM dot altoona dot net
16-Jul-2002 04:20

Someone compared Java to PHP's pass by value.  Java doesn't pass copies of objects to methods "by value" as PHP does.  It passes a copy of the object's reference by value.  It's still the same object.  It's similar to passing a pointer to a structure in C.
php at fts dot net
16-Jul-2002 05:46

Note that creating a reference to a non-existing array element causes that element to be created with a null value.  For example:

var_dump($username);  // => NULL
var_dump($session); // => NULL

$username =& $session['username'];

var_dump($username);  // => NULL
var_dump($session);
 // => array(1) { ["username"]=>  &NULL }

awriiight at yahoo dot com
01-Oct-2002 07:31

you can't pass variables by reference when constructing a string:

$a = "hrack";
$b = "rat" . &$a:

won't work.

rking at rmode dot com
04-Nov-2002 10:21

An interesting thing happens when you use a variable that has been set to a reference as the iterated value in foreach statements. Without unset-ing the iterated value variable before the foreach, each iteration will change the content pointed to by the reference.

$field = &$someVariable;
print $someVariable;

// unset($field); // Without this, the following will probably not work they way you want. It will set the contents of $someVariable to the current iterated value. It is left at the end as the last iterated value.

foreach ($fields as $field)
{
print $field;
}

print $someVariable; // This won't print out the same as the first one

marc at schiffbauer dot net
23-Jan-2003 12:13

If you want to reset a variable which is a reference, you can do that with the unset() function.

$a = "foo";
$b = &$a;

$b references to $a now:
echo $b // => "foo"

$b = NULL; // => now $a is NULL, too

but:

unset($b);
$b = NULL; // => $a is still "foo" and $b is NULL

igjav at cesga dot es
05-Mar-2003 11:12

I've made this testcase to show a case of "self referencing" applicated to arrays. It seems to point out that must be taken with care, but only in terms of when is possible to reference.

It's based on comments over:



Sorry for the careless sense of key names....

<?

 $top =
array
   (
   'name'    =>  'top',
   'parent'  => null,
   'A' =>
     array
       (
       'name'   =>  'A',
       'element1'  =>  &$top,
       'parent' =>  &$top['name'],
       ),
   );

 $top2 =
array
   (
   'name'    =>  'top2',
   'parent'  => null,
   'A' =>
     array
       (
       'name'   =>  'A',
       'element1'  =>  &$top,
       'parent' =>  &$top['name'],
       ),
  );
?>
<pre>
<strong><font color=red>
$top =
 array
   (
   'name'    =>  'top',
   'parent' =>  null,
   'A' =>
     array
       (
      'name'    =>  'A',
       'element1'  =>  &$top,
      'parent'  =>  &$top['name'],
       ),
   );

 $top2 =
 array
   (
   'name'    =>  'top2',
   'parent' =>  null,
   'A' =>
     array
       (
      'name'    =>  'A',
       'element1'  =>  &$top,
      'parent'  =>  &$top['name'],
       ),
  );

</font></strong>
top['A']:
<?
 foreach ( $top['A'] as $k => $v ) {
   printf("$k =&gt; $v\n");
 }
 //
 // What happened?
 //

// Seems you cannot reference an array element before creating "completely" the array
?>

This seems to be "completely" safe:

top2['A']:
<?
 foreach ( $top2['A'] as $k => $v ) {
   printf("$k =&gt; $v\n");
 }
?>

Then more reference tests:

<strong><font color=red>
  $top['A']['parent'] = $top['name'];

  echo($top['A']['parent']);
</font></strong>

<?
  $top['A']['parent'] = $top['name'];

  echo($top['A']['parent']);
?>
<strong><font color=red>
   $refTop = &$top;
   $top['A']['parent'] = $refTop['name'];

  echo($top['A']['parent']);
</font></strong>

<?
  $refTop = &$top;
   $top['A']['parent'] = $refTop['name'];

  echo($top['A']['parent']);
?>
<strong><font color=red>
   $top['A']['parent'] = &$top['name'];

  echo($top['A']['parent']);
</font></strong>

<?
  $top['A']['parent'] = &$top['name'];

  echo($top['A']['parent']);
?>
<strong><font color=red>
  echo($top['A']['element1']['name']);
</font></strong>

<?
  echo($top['A']['element1']['name']);
?>
<strong><font color=red>
  echo($top['A']['element1']['A']['parent']);
</font></strong>

<?
  echo($top['A']['element1']['A']['parent']);
?>
</pre>

php dot net_usernote at CustomCDROM dot de
26-Mar-2003 02:16

It should be pointed out that references are UNROLLED if stored in a session, that is, a copy is made for each reference. If you compare references to hard links in a Unix file system, as this chapter does, think of "storing a session" as a "cp -R".
That really bit me when I nearly finished my library and wondered why I could not use it with PHP's session management. :-/

thomas at zuschneid dot de
14-Apr-2003 06:27

I used objects inside objects, like this:

class ItemClass {
function PrintContainerValue() {
   print $this->container->value;
 }
}

class ContainerClass {
 var $value=5;
 function ContainerClass(&$item) {
  $item->container = &$this;
   $this->item = $item;
}
}

$aContainer = new ContainerClass(new ItemClass);  // 1
$aContainer->value = 10;                          // 2
$aContainer->item->PrintContainerValue();

It was a long quest to figure out why this prints 5, not 10.
But the solution is quite simple:
The "new" in line 1 creates a ContainerClass object with value 5 and an item referencing to this instance.
$aContainer gets only a copy whose "value" is changed in line 2, but item->container still references the first instance with unchanged "value".

Replacing new with &new solved the problem.

chris at chrisderose dot com
24-Apr-2003 11:35

This caused a good deal of confusion for me today, so I thought I'd share my findings. Though one might think a variable *should* lose scope at the end of, say, a for() loop. Its really does not, and any references you set for that variable will continue to point to the variable in question during the next iteration. So for example:

$first_var = NULL;

for ($i=0;$i<5;$i++) {
 $var = "Hello from Iteration $i";
 
 if (!$i)
  $first_var = &$var;
}

echo $first_var;

This code snippet prints out: "Hello from Iteration 5" and not "Hello from Iteration 0" as one might expect at first glance.

The reason why this happens is b/c the scope of $var is being retained at the end of the iteration, and not being unset.

I'm not sure whether this is the expected behavior or if this is a bug. But to accomplish what we first intended ( "Hello from Iteration 0" ) We should write the above code like so:

$first_var = NULL;

for ($i=0;$i<5;$i++) {
 $var = "Hello from Iteration $i";
 
 if (!$i)
 $first_var = &$var;

 unset($var); // <-- Notice that this is the only difference
}

echo $first_var;

I suspect there's a number of scope issues that are similar to this and that it doesn't only affect references. But I don't have the time to find out for sure. (I'd be very interested to hear from someone who does have the time)

aflorio at grad dot inf dot puc-rio dot br
06-May-2003 07:32

The first code snippet above is printing "Hello from Iteration 5" not only because PHP retains variables after a loop, but because you are assigning by reference ($first_var = &$var).
When you do this, $first_var becomes an alias of $var.  Whatever changes you make in $var will also change $first_var (they are actually the same).
If you do:

$first_var = NULL;
for ($i=0;$i<5;$i++) {
  $var = "Hello from Iteration $i";
  if (!$i)
     $first_var = $var;     // Assigning by value
}
echo $first_var;

Then you'll get "Hello from Iteration 0".
As you can see, it's not only a matter of variable scoping.

add a note

<Comparing objects in PHP 5Co reference d�laj�>
 Last updated: Fri, 18 Apr 2003
show source | credits | mirror sites 
Copyright © 2001-2003 The PHP Group
All rights reserved.
This mirror generously provided by: /
Last updated: Sat May 10 05:10:01 2003 CEST