2010-04-26 23 views
62

Parece que no puedo obtener ninguna información coherente sobre esto. Diferentes fuentes parecen decir cosas diferentes y el venerable php.net en sí (aparece) no lo dice explícitamente, aunque debo admitir que solo lo miré rápidamente.¿Se pasan objetos PHP5 por referencia?

En los casos en los que estoy pasando alrededor de los objetos 'pesados', tengo que pasar por referencia, pero no quiero seguir escribiendo:

function foo(TypeName& $obj) 

si puedo continuar con sólo

function foo(TypeName $obj) 

¿Qué dice la norma?

Respuesta

87

Los objetos se pasan (y se asignan) por referencia. No es necesario usar la dirección del operador.

De acuerdo, lo que escribí es una simplificación excesiva, pero se adaptará a sus propósitos. Los documentation estados:

Uno de los puntos clave de la programación orientada a objetos PHP5 que se menciona a menudo es que los "objetos se pasan por referencias por defecto". Esto no es completamente cierto. Esta sección rectifica ese pensamiento general usando algunos ejemplos.

Una referencia de PHP es un alias, que permite dos variables diferentes a escribir en el mismo valor. A partir de PHP5, , una variable de objeto ya no contiene el objeto como valor. Es solo contiene un identificador de objeto que permite a los usuarios del acceso a objetos encontrar el objeto real. Cuando un objeto es enviado por argumento, devuelto o asignado a otra variable, las diferentes variables no son alias: tienen una copia del identificador, que apunta a al mismo objeto.

Para obtener una explicación más detallada (explica la simplificación excesiva así como los identificadores) echa un vistazo a this answer.

+1

¿Puede pasar una referencia de un identificador de objeto? –

+8

Cuando pasa un objeto, todavía está pasando "por valor". Sin embargo, el "valor" NO es el objeto en sí mismo. El valor es el identificador de objeto, que los descriptores de acceso (->) usan para encontrar el objeto. Por lo tanto, cada vez que pasa un objeto o asigna un objeto a otra cosa, "siente" que pasa por referencia. Se "siente" como un alias cuando se usa ->. Pero técnicamente no es un alias, sino una copia de un valor donde el valor es un identificador de objeto. Si fuera un alias, reasignar a un valor completamente diferente cambiaría todos los alias a ese nuevo valor, pero verá que no los convierte en alias. – OCDev

+0

@OCDev así que cada vez que ese objeto se clona? Un poco de desperdicio de recursos. –

3

A partir de PHP 5, todos los objetos se pasan y se asignan por referencia.

En PHP 4, aún necesita especificar dónde quiere que pasen objetos por referencia, utilizando explícitamente el operador &.

8

Desde el PHP manual:

Puede pasar una variable por referencia a una función por lo que la función puede modificar la variable. La sintaxis es la siguiente :

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

$a=5; 
foo($a); 
// $a is 6 here 
?> 

Nota: No hay signo de referencia en una llamada de función - sólo en función de las definiciones . Las definiciones de función son suficientes para pasar correctamente el argumento por referencia. A partir de PHP 5.3.0, recibirá una advertencia diciendo que "llame a tiempo el paso por referencia" es obsoleto cuando se utiliza en & foo ($ & a) ;.

Y a partir de What's New in PHP5:

En PHP 5, la infraestructura del modelo objeto fue reescrito para trabajar con los identificadores de objetos. A menos que explícitamente clonar un objeto mediante el uso de palabras clave el clon que nunca creará detrás de los duplicados escena de sus objetos. En PHP 5, hay ni una necesidad de pasar objetos por referencia ni asignarlos por referencia

Así que, por tanto, la única vez que es necesario utilizar la sintaxis function foo(&$var) es si $ var podría no ser una instancia de una clase.

+0

Estoy tomando una pedante excepción a su declaración "Por lo tanto, la única vez que necesita utilizar la sintaxis << pasar por referencia >> es si $ var podría no ser una instancia de una clase". Hay otra situación importante en la que desea utilizar una referencia por referencia para una instancia de una clase ... Si, como resultado de llamar a una función, desea que se refiera al parámetro que pasó (apunte a) una * instancia * diferente, entonces necesitaría la función para tomar un parámetro pasado por referencia, y en la función asignaría ese parámetro a una instancia diferente. –

1

Sí en PHP5 en adelante, los objetos se pasan por referencia. No es necesario hacer eso explícitamente.

http://www.php.net/manual/en/migration5.oop.php

En PHP 5 hay un nuevo modelo de objetos. El manejo de objetos por PHP ha sido completamente reescrito, lo que permite un mejor rendimiento y más funciones. En versiones anteriores de PHP, los objetos se manejaban como tipos primitivos (por ejemplo, enteros y cadenas). El inconveniente de este método fue que semánticamente todo el objeto se copió cuando se asignó una variable, o pasa como un parámetro a un método. En el nuevo enfoque, los objetos se referencian por manejador, y no por valor (se puede pensar en un manejador como el identificador de un objeto).

2

La respuesta corta es . De Objects and references:

Uno de los puntos clave de la programación orientada a objetos PHP5 que se menciona a menudo es que los "objetos se pasan por referencias por defecto". Esto no es completamente cierto. Esta sección rectifica ese pensamiento general usando algunos ejemplos.

Una referencia de PHP es un alias, que permite dos variables diferentes a escribir en el mismo valor. A partir de PHP5, , una variable de objeto ya no contiene el objeto como valor. Es solo contiene un identificador de objeto que permite a los usuarios del acceso a objetos encontrar el objeto real. Cuando un objeto es enviado por argumento, devuelto o asignado a otra variable, las diferentes variables no son alias: tienen una copia del identificador, que apunta a al mismo objeto.

Lo que importa es que, en el caso de que le preocupa, usted nunca será hacer una copia de un objeto a menos que utilice explícitamente la clon palabra clave en la llamada de función. Si es un alias o un identificador no cambia este hecho.

+0

Para una mayor aclaración, un ejemplo Tengo un objeto de Respuesta PSR-7 transmitido como 'functionName (\ Response $ response)' se comporta como I al escribir esto 'functionName (\ Response & $ response)' en PHP 5+? Cuando esto es cierto, entonces tengo que volver a pensar todo en mi pequeño proyecto. –

+1

@ ZsoltOroszlány En [PSR-7] (http://www.php-fig.org/psr/psr-7/), se requiere que las respuestas sean inmutables por definición. Eso significa que las implementaciones deben llamar 'clone' explícitamente, como en p. [Slim framework] (https://github.com/slimphp/Slim/blob/3.7.0/Slim/Http/Response.php#L182). –

4

Parece ser un poco más preciso, el valor de un objeto se pasa por valor, pero el valor de un objeto en sí es un puntero. Esto es diferente de solo pasar una referencia.

En http://www.php.net/manual/en/language.oop5.references.php, el ejemplo enumerado es agradable. En el primer conjunto, $ a = NULL; no afecta $ b ya que $ a era solo un puntero. En el segundo conjunto, $ c = NULL; hace que $ d sea NULL también, ya que $ d es una referencia a $ c.

<?php 
class A { 
    public $foo = 1; 
} 

$a = new A; 
$b = $a; 
$a->foo = 2; 
$a = NULL; 
echo $b->foo."\n"; // 2 

$c = new A; 
$d = &$c; 
$c->foo = 2; 
$c = NULL; 
echo $d->foo."\n"; // Notice: Trying to get property of non-object... 
?> 
1

Sólo un ejemplo en el paso "objetos" por referencia es útil:

class RefTest1 
{ 
    public $foo; 

    public function __construct(RefTest2 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class RefTest2 
{ 
    public $foo; 

    public function __construct(RefTest1 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class RefTest3 
{ 
    public $foo; 

    public function __construct(RefTest2 &$ref = null) 
    { 
     $this->foo =& $ref; 
    } 
} 

class DoCrossRef 
{ 
    public $refTest1; 
    public $refTest2; 

    public function __construct() 
    { 
     $this->refTest1 = new RefTest1($this->refTest2); 
     $this->refTest2 = new RefTest2($this->refTest1); 
    } 

    public function changeReference() 
    { 
     $this->refTest1 = new RefTest3($this->refTest2); 
    } 
} 

Al final RefTest1 contiene una referencia a RefTest2 y al revés, también si no existiera el objeto RefTest2 en el momento en que se creó RefTest1.

Después de llamar a DoCrossRef->changeReference(), los objetos RefTest2 también contienen una referencia al nuevo objeto RefTest3.

0

Aquí hay otro ejemplo que confirma que los objetos se pasan por referencia.

<?php 

// discussion: https://stackoverflow.com/questions/2715026/are-php5-objects-passed-by-reference#_=_ 
class A { 
    public $foo = 1; 
} 

class B { 
    function inc($obj) { 
     $obj->foo++; 
    } 
} 

$objA = new A(); 
$objB = new B(); 
$objB->inc($objA); 

echo "[" . $objA->foo . "]"; // Outputs [2] 
Cuestiones relacionadas