307 votes

sont des tableaux en php passé par valeur ou par référence ?

Lorsqu’un tableau est passé comme argument à une méthode ou une fonction, il est passé par référence ?

Qu’en est-il de ce faisant :

Désigne $b à $a ?

319voto

Pascal MARTIN Points 195780

Pour la deuxième partie de votre question, voir le tableau à la page du manuel, qui stipule (en les citant) :

Tableau d'affectation implique toujours la valeur de la copie. Utiliser l'opérateur de référence pour copie d'un tableau par référence.

Et l'exemple donné :

<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
             // $arr1 is still array(2, 3)

$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same
?>


Pour la première partie, la meilleure façon d'en être sûr est d'essayer ;-)

Prenons cet exemple de code :

function my_func($a) {
    $a[] = 30;
}

$arr = array(10, 20);
my_func($arr);
var_dump($arr);

Il va donner à cette sortie :

array
  0 => int 10
  1 => int 20

Ce qui indique que la fonction n'a pas modifié le "dehors" de tableau qui a été transmis en tant que paramètre : il est passé comme une copie, et non pas une référence.

Si vous voulez il est passé par référence, vous devrez modifier la fonction, de cette façon :

function my_func(& $a) {
    $a[] = 30;
}

Et le résultat sera le suivant :

array
  0 => int 10
  1 => int 20
  2 => int 30

Comme, cette fois, le tableau a été votée "par référence".


N'hésitez pas à lire les Références Expliqué section du manuel : il doit répondre à certaines de vos questions ;-)

153voto

Kosta Kontos Points 630

En ce qui concerne votre première question, le tableau est passé par référence, SAUF si elle est modifiée dans la méthode ou la fonction que vous appelez. Si vous tentez de modifier un tableau à l'intérieur de la méthode / fonction, une copie de celui-ci est fait d'abord, et ensuite seulement la copie est modifiée. De ce fait, il semble que si le tableau est passé par valeur, alors qu'en réalité il ne l'est pas.

Par exemple, dans ce premier cas, même si vous n'êtes pas de la définition de votre fonction à accepter $my_array par référence (en utilisant le caractère & dans la définition de paramètre), il obtient toujours passés par référence (c'est à dire: vous ne perdez pas la mémoire avec une copie superflue).

function handle_array($my_array) {  

    // ... read from but do not modify $my_array
    print_r($my_array);

    // ... $my_array effectively passed by reference since no copy is made
}

Toutefois, si vous modifier un tableau, une copie en est faite en premier (qui utilise plus de mémoire, mais les feuilles de votre tableau d'origine non affectée).

function handle_array($my_array) {

    // ... modify $my_array
    $my_array[] = "New value";

    // ... $my_array effectively passed by value since requires local copy
}

FYI - ce qui est connu comme "paresseux copie" ou "copie à l'écriture" - plus d'infos ici: http://www.thedeveloperday.com/php-lazy-copy/

98voto

nevvermind Points 1083

Je pense que je suis en train d'écrire cela pour moi-même. Je devrais avoir un blog ou quelque chose...

Chaque fois que les gens parlent de références (ou pointeurs), ils finissent généralement dans un logomachy (il suffit de regarder ce thread!).
PHP étant un vénérable langue, j'ai pensé que je devrais ajouter à la confusion (même si ceci est un résumé des réponses ci-dessus). Parce que, bien que deux personnes peuvent avoir raison en même temps, vous êtes mieux de simplement faire craquer leurs têtes ensemble en une seule réponse.

Tout d'abord, vous devez savoir que vous n'êtes pas un pédant si vous ne répondez pas dans un noir et blanc façon. Les choses sont plus compliquées que "oui/non".

Comme vous le verrez, le tout par valeur ou par référence chose est très lié à ce que sont exactement ce que tu fais avec ce tableau dans votre méthode de la fonction/champ d'application: le lire ou le modifier?

Ce n'PHP dit? (aka "le changement-sage")

Le manuel dit ceci (l'emphase est mienne):

Par défaut, les arguments d'une fonction sont passés par valeur (de sorte que si l' la valeur de l'argument dans la fonction est changé, il n'est pas modifié en dehors de la fonction). Pour permettre une fonction pour modifierson arguments, ils doivent être passés par référence.

Pour avoir un argument à un fonction toujours passés par référence, ajouter une esperluette (&) à la nom d'argument dans la définition de la fonction

Aussi loin que je peux dire, lors de la grande, sérieuse, honnête à Dieu programmeurs parler de références, ils ont l'habitude de parler de modifier la valeur de référence. Et c'est exactement ce que le manuel parle de: hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value".

Il y a un autre cas qu'ils ne parlent pas, mais: si je n'ai pas changer quoi que ce soit - tout juste de lire?
Que faire si vous passer un tableau à une méthode qui n'est pas explicitement les marques de référence, et on ne change pas le tableau dans le domaine de la fonction? Alias:

<?php
function printArray($array) {}
$x = array(1);
printArray($x);

Lire sur, mon compagnon de voyage.

Ce n'PHP? (aka "ram")

La même grosse et grave de programmeurs, quand ils se font encore plus grave, ils parlent de "optimisations de mémoire" en ce qui concerne les références. Donc ne PHP. Parce qu' PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting, c'est pourquoi.

Il ne serait pas idéal pour passer des tableaux de grande à diverses fonctions, et le PHP pour faire des copies d'eux (c'est ce "passage par valeur" ne, après tout):

<?php

// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from you RAM
$x = array_fill(0, 10000, 1); 

// pass by value, right? RIGHT?
function readArray($arr) { // <-- a new symbol (variable) gets created here
    echo count($arr); // let's just read the array
}

readArray($x);

Eh bien maintenant, si c'était réellement passé par valeur, nous aurions des 3mb+ RAM disparu, parce qu'il y a deux copies de ce tableau, à droite?

Mal. Tant que nous ne changeons pas l' $arr variable, c'est une référence, de la mémoire-sage. Vous n'avez tout simplement pas le voir. C'est pourquoi PHP mentionne l'utilisateur des terres références lorsque l'on parle de &$someVar, à la distinction entre l'interne et explicite (avec esperluette).

Faits

Donc, when an array is passed as an argument to a method or function is it passed by reference?

Je suis venu avec trois (oui, trois) cas:
a) la méthode/fonction ne lit que l'argument de tableau
b) la méthode/fonction modifie l'argument de tableau
c) la méthode/fonction array argument est explicitement marqué comme une référence (avec une esperluette)


Tout d'abord, voyons voir combien de mémoire que le tableau fait mange (exécuter ici):

<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840

Ce nombre d'octets. Grand.

a) la méthode/fonction ne lit que l'argument de tableau

Maintenant, nous allons faire une fonction qui ne lit que le dit tableau comme argument et nous allons voir combien de mémoire à la lecture de la logique:

<?php

function printUsedMemory($arr) 
{
    $start_memory = memory_get_usage();

    count($arr);       // read
    $x = $arr[0];      // read (+ minor assignment)
    $arr[0] - $arr[1]; // read

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1); // this is 1331840 bytes
printUsedMemory($x);

Envie de deviner? Je reçois 80! Voir pour vous-même. C'est la partie que le manuel PHP omet. Si l' $arr param était réellement passé par valeur, vous devriez voir quelque chose de similaire 1331840 octets. Il semble qu' $arr se comporte comme une référence, n'est-ce pas? C'est parce que c' est une des références de l'interne.

b) la méthode/fonction modifie l'argument de tableau

Maintenant, nous allons écrire à ce param, au lieu de lire:

<?php

function printUsedMemory($arr)
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

Encore une fois, voyez par vous-même, mais, pour moi, c'est très proche de la 1331840. Donc, dans ce cas, le tableau est en fait la copie $arr.

c) la méthode/fonction array argument est explicitement marqué comme une référence (avec une esperluette)

Maintenant, nous allons voir combien de mémoire d'une opération d'écriture à une référence explicite prend (exécuter ici) - note de l'esperluette à la signature de la fonction:

<?php

function printUsedMemory(&$arr) // <----- explicit, user-land, pass-by-reference
{
    $start_memory = memory_get_usage();

    $arr[0] = 1; // WRITE!

    echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

Mon pari est que vous obtenez 200 max! Donc, ce mange environ autant de mémoire que la lecture à partir d'un non-commercial param.

Conclusions

a) la méthode/fonction ne lit que l'argument de tableau => implicite (interne) de référence
b) la méthode/fonction modifie l'argument de tableau => valeur
c) la méthode/fonction array argument est explicitement marqué comme une référence (avec une esperluette) => explicite (user-land) de référence

Ou ceci:
- non-commercial de la matrice de param: passé par référence; l'écriture des opérations de modifier une nouvelle copie de la matrice, la copie qui est créé lors de la première écriture;
- esperluette tableau param: passé par référence; l'écriture des opérations de modifier le tableau d'origine.

Rappelez - vous- PHP n'a une valeur exemplaire , au moment de vous écrire à la non-esperluette tableau param. C'est ce qu' copy-on-write moyens. J'aimerais vous montrer le C source de ce comportement, mais c'est grudge. Mieux utiliser xdebug_debug_zval().

Pascal MARTIN a raison. Kosta Kontos a été encore plus.

Réponse

Il dépend.

5voto

cballou Points 13804

Lorsqu’un tableau est passé à une méthode ou une fonction en PHP, il est passé par valeur, sauf si vous lui passez explicitement par référence, comme suit :

Dans votre deuxième question, n’est pas une référence à , mais une copie de `` .

Beaucoup comme le premier exemple, vous pouvez référencer `` en procédant comme suit :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X