Les variables PHP sont-elles transmises par valeur ou par référence?

Réponses:

312

C'est en valeur selon la documentation PHP .

Par défaut, les arguments de fonction sont passés par valeur (de sorte que si la valeur de l'argument dans la fonction est modifiée, elle ne soit pas modifiée en dehors de la fonction). Pour permettre à une fonction de modifier ses arguments, ils doivent être passés par référence.

Pour qu'un argument d'une fonction soit toujours passé par référence, ajoutez une esperluette ( & ) au nom de l'argument dans la définition de la fonction.

<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}

$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>
Michael Stum
la source
4
J'avais aussi ce doute (débutant) - donc juste pour être clair, ce serait la même chose que $str = add_some_extra($str);si je n'utilisais pas la référence, non? alors quelle est la vraie valeur ajoutée de cela?
Obmerk Kronen
7
@Obmerk Si vous n'utilisiez pas l'esperluette pour signifier par référence, ce ne serait pas équivalent. Remarquez que la fonction n'a pas de déclaration de retour, donc $strserait affectée null, dans votre cas.
The Unknown Dev
si vous le faites de cette façon @ObmerkKronen, vous devrez également renvoyer la valeur et la récupérer dans votre code. Sinon, la variable initiale restera la même.
Nabeel Khan
Je me demande si le renvoi par référence présente des avantages en termes de performances ou non? Je passe un grand tableau et par défaut c'est passer par valeur. Donc, si j'utilise l'appel par référence, y aura-t-il un avantage en termes de performances ??? (en gardant les valeurs du tableau inchangées pendant tout le processus)
Choxx
4
le véritable avantage est que vous pouvez manipuler / renvoyer plusieurs valeurs. Vous pouvez également passer des variables par référence et laisser la fonction renvoyer quelque chose.
Martin Schneider
65

En PHP, par défaut, les objets sont passés en tant que copie de référence à un nouvel objet.

Voir cet exemple .............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
   $obj->abc = 30;
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 30

Maintenant, voyez ceci ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 10 not 20 same as java does.

Maintenant, voyez ceci ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue(&$obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 20 not possible in java.

j'espère que vous pouvez comprendre cela.

hardik
la source
1
Cela illustre très bien le fonctionnement des objets PHP.
Frederik Krautwald,
2
1er ex, la valeur de la référence de l'obj est passée à la fonction, les modifications de l'obj utilisant la nouvelle référence se refléteront sur toutes les autres références pointant vers le même obj. 2ème ex, encore une fois la VALEUR de la référence de l'obj est passée à la fonction, la fonction change la valeur de la référence pour pointer vers un nouvel obj, l'ancien obj reste le même. 3e ex, la référence de la valeur de la référence de l'obj est passée dans la fonction, donc les changements dans la fonction opèrent sur le même obj.
s-hunter
Des exemples parfaits et exactement ce que je pensais se passerait. Je suis un nouveau venu en PHP (de fond Javascript / node.js) et parfois c'est difficile de comprendre ce qui se passe, mais c'est très clair!
TKoL
Cet exemple est inutilement compliqué. $yn'est pas nécessaire - il n'y a rien function changeValuequi exige qu'il soit à l'intérieur class Y, de sorte que s'emmêle deux concepts sans rapport. Je voudrais passer function changeValueà la portée extérieure, juste au-dessus $x = new X();. Supprimez toutes les références à $y. Il est maintenant plus facile de voir que les deux premiers exemples laissent $ x seul, et le troisième change son contenu en new Y(). Ce qui serait plus facile de voir si vous pratiqué le dumping typede $x- le fait que les deux Xet Yarriver à inclure un $abcchamp est également sans rapport avec ce qui est démontré
ToolmakerSteve
60

Il semble que beaucoup de gens soient confus par la façon dont les objets sont passés aux fonctions et par ce qui passe par référence. Les variables d'objets sont toujours passées par valeur, c'est juste la valeur qui est passée en PHP5 qui est un handle de référence. Comme preuve:

<?php
class Holder {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

function swap($x, $y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Les sorties:

a, b

Passer par référence signifie que nous pouvons modifier les variables qui sont vues par l'appelant. Ce que le code ci-dessus ne fait clairement pas. Nous devons changer la fonction de swap pour:

<?php
function swap(&$x, &$y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Les sorties:

b, a

afin de passer par référence.

grom
la source
18
Je pense que cette preuve est une mauvaise interprétation. Il semble que vous essayiez d'échanger des références. Vous avez un problème avec la façon dont les objets sont attribués. Vous réaffectez la référence qui est immuable. C'est la valeur qu'il pointe qui peut être modifiée de l'intérieur. La redéfinition du swap passe maintenant ** x, ce qui vous permet de changer * x. Le problème est de penser que $ x = $ y changerait ce à quoi $ x pointe à l'origine.
grantwparks
9
Ce n'est pas une preuve . La sortie du premier exemple correspond exactement à ce que vous attendez si la valeur actuelle de l'objet entier était transmise à la swapfonction; en d'autres termes, si les objets étaient "passés par valeur". D'un autre côté, c'est aussi exactement ce à quoi vous vous attendriez si un descripteur d'objet était passé à la fonction, ce qui se passe en fait. Votre code ne fait pas de distinction entre ces deux cas.
EML
31

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

En PHP 5, il existe un nouveau modèle d'objet. La gestion des objets par PHP a été complètement réécrite, permettant de meilleures performances et plus de fonctionnalités. Dans les versions précédentes de PHP, les objets étaient traités comme des types primitifs (par exemple des entiers et des chaînes). L'inconvénient de cette méthode était que sémantiquement l'objet entier était copié lorsqu'une variable était assignée, ou passée en paramètre à une méthode. Dans la nouvelle approche, les objets sont référencés par handle, et non par valeur (on peut penser à un handle comme identifiant d'objet).

Karl Seguin
la source
25

Les variables PHP sont attribuées par valeur, transmises aux fonctions par valeur, et lorsqu'elles contiennent / représentent des objets, elles sont transmises par référence. Vous pouvez forcer les variables à passer par référence en utilisant un &

Attribué par valeur / exemple de référence:

$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";

print ("var1: $var1, var2: $var2, var3: $var3);

sortirait

var1: test, var2: test final, var3: test final

Passé par valeur / référence exampe:

$var1 = "foo";
$var2 = "bar";

changeThem($var1, $var2);

print "var1: $var1, var2: $var2";

function changeThem($var1, &$var2){
    $var1 = "FOO";
    $var2 = "BAR";
}

produirait:

var1: foo, var2 BAR

Variables d'objets passées par référence exampe:

class Foo{
    public $var1;

    function __construct(){
        $this->var1 = "foo";
    }

    public function printFoo(){
        print $this->var1;
    }
}


$foo = new Foo();

changeFoo($foo);

$foo->printFoo();

function changeFoo($foo){
    $foo->var1 = "FOO";
}

Produirait:

FOO

(ce dernier exemple pourrait être mieux probablement ...)

cmcculloh
la source
2
Les "objets" ne sont pas des valeurs en PHP5 et ne peuvent pas être "passés". La valeur de $fooest un pointeur sur un objet . $fooest passé par valeur à la fonction changeFoo(), car il changeFoo()n'a pas déclaré son paramètre avec a &.
newacct
9

Vous pouvez passer une variable à une fonction par référence. Cette fonction pourra modifier la variable d'origine.

Vous pouvez définir le passage par référence dans la définition de fonction:

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

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>
Mahsin
la source
6

Vous pouvez le faire de toute façon.

mettez un symbole «&» devant et la variable que vous passez devient une seule et même chose que son origine. c'est à dire: vous pouvez passer par référence, plutôt que d'en faire une copie.

alors

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.
Bingy
la source
2
Ceci est obsolète et génère un avertissement
fijiaaron
5

Les variables contenant des types primitifs sont passées par valeur en PHP5. Les variables contenant des objets sont passées par référence. Il y a un article assez intéressant du Linux Journal de 2006 qui mentionne cela et d'autres différences OO entre 4 et 5.

http://www.linuxjournal.com/article/9170

Polsonby
la source
Toutes les variables sont passées par valeur en PHP si le paramètre de la fonction n'a pas &.
newacct
1

Les objets sont passés par référence en PHP 5 et par valeur en PHP 4. Les variables sont passées par valeur par défaut!

Lisez ici: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

Miha
la source
Les "objets" ne sont pas des valeurs en PHP5 et ne peuvent pas être "passés". Toutes les variables sont passées par valeur si le paramètre de la fonction passée à n'a pas &.
newacct
@newacct pas tout à fait? Les objets sont quelque peu passés par référence . Je pense avoir observé que les objets php peuvent être modifiés par des fonctions même lorsqu'ils ne sont pas définis avec &devant les paramètres dans la définition - s'ils étaient passés par valeur, l'objet contenu dans la portée qui appelait la fonction avec lui comme paramètre le ferait pas être affecté.
Félix Gagnon-Grenier
3
@ FélixGagnon-Grenier: Encore une fois, les "objets" ne sont pas des valeurs et ne peuvent pas être "passés". Vous ne pouvez pas avoir une "variable" en PHP5 dont la valeur est un "objet", vous ne pouvez avoir qu'une valeur qui est une référence d'objet (c'est-à-dire un pointeur vers un objet). Bien sûr, vous pouvez passer ou affecter un pointeur à un objet par valeur et modifier l'objet vers lequel il pointe en appelant une méthode qui effectue une telle modification. Cela n'a rien à voir avec le renvoi par renvoi. De quel type est une valeur et si un paramètre est passe-par-valeur / passe-par-référence sont des choses indépendantes et orthogonales.
newacct
1
class Holder
{
    private $value;

    public function __construct( $value )
    {
        $this->value = $value;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function setValue( $value )
    {
        return $this->value = $value;
    }
}

class Swap
{       
    public function SwapObjects( Holder $x, Holder $y )
    {
        $tmp = $x;

        $x = $y;

        $y = $tmp;
    }

    public function SwapValues( Holder $x, Holder $y )
    {
        $tmp = $x->getValue();

        $x->setValue($y->getValue());

        $y->setValue($tmp);
    }
}


$a1 = new Holder('a');

$b1 = new Holder('b');



$a2 = new Holder('a');

$b2 = new Holder('b');


Swap::SwapValues($a1, $b1);

Swap::SwapObjects($a2, $b2);



echo 'SwapValues: ' . $a2->getValue() . ", " . $b2->getValue() . "<br>";

echo 'SwapObjects: ' . $a1->getValue() . ", " . $b1->getValue() . "<br>";

Les attributs sont toujours modifiables lorsqu'ils ne sont pas transmis par référence, donc méfiez-vous.

Production:

SwapObjects: b, a SwapValues: a, b

Ricardo Saracino
la source
1

Pour tous ceux qui rencontreront cela à l'avenir, je veux partager ce joyau des documents PHP, publié par un utilisateur anonyme :

Il semble y avoir une certaine confusion ici. La distinction entre pointeurs et références n'est pas particulièrement utile. Le comportement de certains des exemples «complets» déjà publiés peut être expliqué en termes unificateurs plus simples. Le code de Hayley, par exemple, fait EXACTEMENT ce à quoi vous devez vous attendre. (En utilisant> = 5.3)

Premier principe: un pointeur stocke une adresse mémoire pour accéder à un objet. Chaque fois qu'un objet est attribué, un pointeur est généré. (Je n'ai pas encore fouillé TROP profondément dans le moteur Zend, mais pour autant que je sache, cela s'applique)

2ème principe, et source de plus de confusion: le passage d'une variable à une fonction se fait par défaut comme un passage de valeur, c'est-à-dire que vous travaillez avec une copie. "Mais les objets sont passés par référence!" Une idée fausse commune ici et dans le monde Java. Je n'ai jamais dit de quoi. Le passage par défaut se fait par valeur. Toujours. CE qui est copié et transmis, cependant, est le pointeur. Lorsque vous utilisez le "->", vous accéderez bien sûr aux mêmes internes que la variable d'origine dans la fonction appelant. L'utilisation de "=" ne fonctionnera qu'avec des copies.

3ème principe: "&" définit automatiquement et définitivement un autre nom / pointeur de variable sur la même adresse mémoire qu'autre chose jusqu'à ce que vous les découpliez. Il est correct d'utiliser le terme "alias" ici. Pensez-y comme joignant deux pointeurs à la hanche jusqu'à ce qu'ils soient séparés de force avec "unset ()". Cette fonctionnalité existe à la fois dans la même portée et lorsqu'un argument est passé à une fonction. Souvent, l'argument passé est appelé «référence», en raison de certaines distinctions entre «passage par valeur» et «passage par référence» qui étaient plus claires en C et C ++.

N'oubliez pas: les pointeurs vers les objets, et non les objets eux-mêmes, sont passés aux fonctions. Ces pointeurs sont des COPIES de l'original, sauf si vous utilisez "&" dans votre liste de paramètres pour transmettre réellement les originaux. Ce n'est que lorsque vous creusez dans les internes d'un objet que les originaux changeront.

Et voici l'exemple qu'ils fournissent:

<?php

//The two are meant to be the same
$a = "Clark Kent"; //a==Clark Kent
$b = &$a; //The two will now share the same fate.

$b="Superman"; // $a=="Superman" too.
echo $a;
echo $a="Clark Kent"; // $b=="Clark Kent" too.
unset($b); // $b divorced from $a
$b="Bizarro";
echo $a; // $a=="Clark Kent" still, since $b is a free agent pointer now.

//The two are NOT meant to be the same.
$c="King";
$d="Pretender to the Throne";
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByValue($c, $d);
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByRef($c, $d);
echo $c."\n"; // $c=="Pretender to the Throne"
echo $d."\n"; // $d=="King"

function swapByValue($x, $y){
$temp=$x;
$x=$y;
$y=$temp;
//All this beautiful work will disappear
//because it was done on COPIES of pointers.
//The originals pointers still point as they did.
}

function swapByRef(&$x, &$y){
$temp=$x;
$x=$y;
$y=$temp;
//Note the parameter list: now we switched 'em REAL good.
}

?>

J'ai écrit un article de blog détaillé et détaillé sur ce sujet pour JavaScript , mais je pense qu'il s'applique tout aussi bien à PHP, C ++ et à tout autre langage où les gens semblent confus au sujet du passage par valeur par rapport au passage par référence.

De toute évidence, PHP, comme C ++, est un langage qui prend en charge le passage par référence. Par défaut, les objets sont passés par valeur. Lorsque vous travaillez avec des variables qui stockent des objets, il est utile de voir ces variables comme des pointeurs (car c'est fondamentalement ce qu'elles sont, au niveau de l'assemblage). Si vous passez un pointeur par valeur, vous pouvez toujours "tracer" le pointeur et modifier les propriétés de l'objet pointé. Ce que vous ne pouvez pas faire, c'est qu'il pointe vers un autre objet. Ce n'est que si vous déclarez explicitement qu'un paramètre est passé par référence que vous pourrez le faire.

AleksandrH
la source
0

En fait, les deux méthodes sont valides, mais cela dépend de vos besoins. Les valeurs de référence par référence ralentissent souvent votre script. Il est donc préférable de passer les variables par valeur en considérant le temps d'exécution. Le flux de code est également plus cohérent lorsque vous transmettez des variables par valeur.

atif
la source
0

Utilisez-le pour les fonctions lorsque vous souhaitez simplement modifier la variable d'origine et lui redonner le même nom de variable avec sa nouvelle valeur affectée.

function add(&$var){ // The &amp; is before the argument $var
   $var++;
}
$a = 1;
$b = 10;
add($a);
echo "a is $a,";
add($b);
echo " a is $a, and b is $b"; // Note: $a and $b are NOT referenced
PPL
la source
-7

Dépend de la version, 4 est par valeur, 5 est par référence.

Karl Seguin
la source
11
Je ne pense pas que ce soit vrai.
Nick Heiner
@Karl Seguin, c'est en partie vrai. Avant PHP5, les objets par défaut étaient passés par valeur mais depuis 5 ils sont passés par gestionnaire, qui en pratique peut être traité comme une référence (à quelques exceptions près) car nous pouvons modifier les propriétés des objets via eux php.net/manual/en/language. oop5.references.php .
Adam Faryna