downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Qué NO son las Referencias> <Qué son las Referencias
Last updated: Fri, 20 May 2011

view this page in

Qué hacen las Referencias

Hay tres operaciones básicas que se realizan usando referencias: asignar por referncia, pasar por referencia, y devolver por referencia. En esta sección se dará una introducción a estas operaciones, con enlaces para una lectura complementaria.

Asignar por Referencia

En la primera de estas operaciones, las referencias de PHP permiten hacer que dos variables hagan referencia al mismo contenido. Es decir, cuando se hace:

<?php
$a 
=& $b;
?>
significa que $a y $b apuntan al mismo contenido.

Note:

$a y $b aquí son completamente iguales. $a no está apuntando a $b o viceversa. $a y $b están apuntando al mismo lugar.

Note:

Si se asigna, pasa, o devuelve una variable no definida por referencia, la variable se creará.

Example #1 Usar referencias con variables no definidas

<?php
function foo(&$var) { }

foo($a); // $a es "creada" y asignada 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)
?>

Se puede usar la misma sintaxis con funciones que devuelven referencias y con el operador new (desde PHP 4.0.4 y anterior a PHP 5.0.0):

<?php
$foo 
=& find_var($bar);
?>
Desde PHP 5, new devuelve una referencia automáticamente, por lo que usar =& en este contexto es obsoleto y produce un mensaje E_DEPRECATED en PHP 5.3 y posteriores, y un mensaje E_STRICT en versiones anteriores. (Técnicamente, la diferencia es que, en PHP 5, las variables de objetos, como los recursos, son meros punteros a la información del objeto actual, por lo que estas referencias a objetos no son "referencias" en el mismo sentido usado antes (alias). Para más información, véase Objetos y referencias.)

Warning

Si se asigna una referencia a una varible declarada global dentro de una función, la referencia será visible sólo dentro de la función. Se puede evitar esto usando la matriz $GLOBALS.

Example #2 Refenciar variables globales dentro de funciones

<?php
$var1 
"Variable de ejemplo";
$var2 "";

function 
referencias_globales($usar_globals)
{
    global 
$var1$var2;
    if (!
$usar_globals) {
        
$var2 =& $var1// visible sólo dentro de la función
    
} else {
        
$GLOBALS["var2"] =& $var1// visible también en el contexto global
    
}
}

referencias_globales(false);
echo 
"var2 está establecida a '$var2'\n"// var2 está establecida a ''
referencias_globales(true);
echo 
"var2 está establecida a '$var2'\n"// var2 está establecida a 'Variable de ejemplo'
?>
Piense en global $var; como simplificación de $var =& $GLOBALS['var'];. De este modo, al asignar otra referencia a $var sólo cambia la referencia de la variable local.

Note:

Si se asigna un valor a una variable con referencias en una sentencia foreach, también se modifican las referencias.

Example #3 Referencias y la sentencia foreach

<?php
$ref 
0;
$fila =& $ref;
foreach (array(
123) as $fila) {
    
// hacer algo
}
echo 
$ref// 3 - último elemento de la matriz iterada
?>

Mientras que no sea estrictamente una asignación por referencias, las expresiones creadas con el constructor de lenguaje array() también pueden comportarse como tales prefijando & al elemento del array a añadir. Ejemplo:

<?php
$a 
1;
$b = array(23);
$arr = array(&$a, &$b[0], &$b[1]);
$arr[0]++; $arr[1]++; $arr[2]++;
/* $a == 2, $b == array(3, 4); */
?>

Observe, sin embargo, que las referencias dentro de arrays son potencialmente peligrosas. Realizar una asignación normal (no por referencia) con una referencia en el lado derecho no convierte el lado izquierdo en una referencia, pero las referencias dentro de arrays son conservadas en estas asignaciones normales. Esto también se aplica a las llamadas a funciones donde el array es pasado por valor. Ejemplo:

<?php
/* Asignación de variables escalares */
$a 1;
$b =& $a;
$c $b;
$c 7//$c no es una referencia; no cambia $a o $b

/* Asignación de variables de array */
$arr = array(1);
$a =& $arr[0]; // $a y $arr[0] son el mismo conjunto de referencias
$arr2 $arr// ¡no es una asignación por referencia!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* ¡El contenido de $arr se cambia incluso si no es una referencia! */
?>
En otras palabras, el comportamiento de las referencias de arrays está definido en una base elemento-por-elemento; el comportamiento de las referencias de elementos individuales está desasociado del estado de la referencia del array contenedor.

Pasar por Referencia

Lo segundo que hacen las referencias es pasar variables por referencia. Esto se lleva a cabo haciendo que una variable local en una función y una variable en el ámbito de la llamada referencien al mismo contenido. Ejemplo:

<?php
function foo(&$var)
{
    
$var++;
}

$a=5;
foo($a);
?>
hará que $a sea 6. Esto sucede porque en la función foo la variable $var hace referencia al mismo contenido que $a. Para más información sobre esto, lea la sección pasar por referencia.

Devolver por Referencia

Lo tercero que hacen las referncias es devolver por referencia.



Qué NO son las Referencias> <Qué son las Referencias
Last updated: Fri, 20 May 2011
 
add a note add a note User Contributed Notes Qué hacen las Referencias
elrah [] polyptych [dot] com 28-Jan-2011 06:38
It appears that references can have side-effects.  Below are two examples.  Both are simply copying one array to another.  In the second example, a reference is made to a value in the first array before the copy.  In the first example the value at index 0 points to two separate memory locations. In the second example, the value at index 0 points to the same memory location.

I won't say this is a bug, because I don't know what the designed behavior of PHP is, but I don't think ANY developers would expect this behavior, so look out.

An example of where this could cause problems is if you do an array copy in a script and expect on type of behavior, but then later add a reference to a value in the array earlier in the script, and then find that the array copy behavior has unexpectedly changed.

<?php
// Example one
$arr1 = array(1);
echo
"\nbefore:\n";
echo
"\$arr1[0] == {$arr1[0]}\n";
$arr2 = $arr1;
$arr2[0]++;
echo
"\nafter:\n";
echo
"\$arr1[0] == {$arr1[0]}\n";
echo
"\$arr2[0] == {$arr2[0]}\n";

// Example two
$arr3 = array(1);
$a =& $arr3[0];
echo
"\nbefore:\n";
echo
"\$a == $a\n";
echo
"\$arr3[0] == {$arr3[0]}\n";
$arr4 = $arr3;
$arr4[0]++;
echo
"\nafter:\n";
echo
"\$a == $a\n";
echo
"\$arr3[0] == {$arr3[0]}\n";
echo
"\$arr4[0] == {$arr4[0]}\n";
?>
akinaslan at gmail dot com 09-Jan-2011 01:31
In this example class name is different from its first function and however there is no construction function. In the end as you guess "a" and "c" are equal. So if there is no construction function at same time class and its first function names are the same, "a" and "c" doesn't equal forever. In my opinion php doesn't seek any function for the construction as long as their names differ from each others.

<?php
class reftest_new
{
    public
$a = 1;
    public
$c = 1;

    public function
reftest()
    {
       
$b =& $this->a;
       
$b++;
    }

    public function
reftest2()
    {
       
$d =& $this->c;
       
$d++;
    }
}

$reference = new reftest_new();

$reference->reftest();
$reference->reftest2();

echo
$reference->a; //Echoes 2.
echo $reference->c; //Echoes 2.
?>
Amaroq 16-Jan-2010 11:14
I think a correction to my last post is in order.

When there is a constructor, the strange behavior mentioned in my last post doesn't occur. My guess is that php was treating reftest() as a constructor (maybe because it was the first function?) and running it upon instantiation.

<?php
class reftest
{
    public
$a = 1;
    public
$c = 1;

    public function
__construct()
    {
        return
0;
    }

    public function
reftest()
    {
       
$b =& $this->a;
       
$b++;
    }

    public function
reftest2()
    {
       
$d =& $this->c;
       
$d++;
    }
}

$reference = new reftest();

$reference->reftest();
$reference->reftest2();

echo
$reference->a; //Echoes 2.
echo $reference->c; //Echoes 2.
?>
Amaroq 15-Jan-2010 02:08
When using references in a class, you can reference $this-> variables.

<?php
class reftest
{
    public
$a = 1;
    public
$c = 1;

    public function
reftest()
    {
       
$b =& $this->a;
       
$b = 2;
    }

    public function
reftest2()
    {
       
$d =& $this->c;
       
$d++;
    }
}

$reference = new reftest();

$reference->reftest();
$reference->reftest2();

echo
$reference->a; //Echoes 2.
echo $reference->c; //Echoes 2.
?>

However, this doesn't appear to be completely trustworthy. In some cases, it can act strangely.

<?php
class reftest
{
    public
$a = 1;
    public
$c = 1;

    public function
reftest()
    {
       
$b =& $this->a;
       
$b++;
    }

    public function
reftest2()
    {
       
$d =& $this->c;
       
$d++;
    }
}

$reference = new reftest();

$reference->reftest();
$reference->reftest2();

echo
$reference->a; //Echoes 3.
echo $reference->c; //Echoes 2.
?>

In this second code block, I've changed reftest() so that $b increments instead of just gets changed to 2. Somehow, it winds up equaling 3 instead of 2 as it should.
strata_ranger at hotmail dot com 26-Sep-2009 10:29
An interesting if offbeat use for references:  Creating an array with an arbitrary number of dimensions.

For example, a function that takes the result set from a database and produces a multidimensional array keyed according to one (or more) columns, which might be useful if you want your result set to be accessible in a hierarchial manner, or even if you just want your results keyed by the values of each row's primary/unique key fields.

<?php
function array_key_by($data, $keys, $dupl = false)
/*
 * $data  - Multidimensional array to be keyed
 * $keys  - List containing the index/key(s) to use.
 * $dupl  - How to handle rows containing the same values.  TRUE stores it as an Array, FALSE overwrites the previous row.
 *         
 * Returns a multidimensional array indexed by $keys, or NULL if error.
 * The number of dimensions is equal to the number of $keys provided (+1 if $dupl=TRUE).
 */  
{
   
// Sanity check
   
if (!is_array($data)) return null;
   
   
// Allow passing single key as a scalar
   
if (is_string($keys) or is_integer($keys)) $keys = Array($keys);
    elseif (!
is_array($keys)) return null;

   
// Our output array
   
$out = Array();
   
   
// Loop through each row of our input $data
   
foreach($data as $cx => $row) if (is_array($row))
    {
     
     
// Loop through our $keys
     
foreach($keys as $key)
      {
       
$value = $row[$key];

        if (!isset(
$last)) // First $key only
       
{
          if (!isset(
$out[$value])) $out[$value] = Array();
         
$last =& $out; // Bind $last to $out
       
}
        else
// Second and subsequent $key....
       
{
          if (!isset(
$last[$value])) $last[$value] = Array();
        }

       
// Bind $last to one dimension 'deeper'.
        // First lap: was &$out, now &$out[...]
        // Second lap: was &$out[...], now &$out[...][...]
        // Third lap:  was &$out[...][...], now &$out[...][...][...]
        // (etc.)
       
$last =& $last[$value];
      }
     
      if (isset(
$last))
      {
       
// At this point, copy the $row into our output array
       
if ($dupl) $last[$cx] = $row; // Keep previous
       
else       $last = $row; // Overwrite previous
     
}
      unset(
$last); // Break the reference
   
}
    else return
NULL;
   
   
// Done
   
return $out;
}

// A sample result set to test the function with
$data = Array(Array('name' => 'row 1', 'foo' => 'foo_a', 'bar' => 'bar_a', 'baz' => 'baz_a'),
              Array(
'name' => 'row 2', 'foo' => 'foo_a', 'bar' => 'bar_a', 'baz' => 'baz_b'),
              Array(
'name' => 'row 3', 'foo' => 'foo_a', 'bar' => 'bar_b', 'baz' => 'baz_c'),
              Array(
'name' => 'row 4', 'foo' => 'foo_b', 'bar' => 'bar_c', 'baz' => 'baz_d')
              );

// First, let's key it by one column (result: two-dimensional array)
print_r(array_key_by($data, 'baz'));

// Or, key it by two columns (result: 3-dimensional array)
print_r(array_key_by($data, Array('baz', 'bar')));

// We could also key it by three columns (result: 4-dimensional array)
print_r(array_key_by($data, Array('baz', 'bar', 'foo')));

?>
dnhuff at acm dot org 09-Jun-2008 06:33
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.
Drewseph 29-May-2008 11: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.
Amaroq 01-Apr-2008 06: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"
?>
charles at org oo dot com 19-Oct-2007 10: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);
?>
Hlavac 09-Oct-2007 09: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!
dovbysh at gmail dot com 06-Jul-2007 07: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

?>
amp at gmx dot info 08-Jun-2007 05: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)
firespade at gmail dot com 03-Apr-2007 02: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
php at hood dot id dot au 05-Mar-2007 06: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)
ladoo at gmx dot at 17-Apr-2005 09: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
?>
php.devel at homelinkcs dot com 15-Nov-2004 11: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.
joachim at lous dot org 10-Apr-2003 10: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.

 
show source | credits | stats | sitemap | contact | advertising | mirror sites