Question

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

Et si on faisait ceci :

$a = array(1,2,3);
$b = $a;

Est $b une référence à $a?

Était-ce utile?

La solution

Pour la deuxième partie de votre question, consultez le du manuel , qui indique (citant) :

  

Affectation Array implique toujours la valeur   copier. Utilisez l'opérateur de référence   copier un tableau de 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'être sûr est d'essayer; -)

Considérons 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 tableau « dehors » qui a été passé en paramètre. Il est passé comme une copie, et non une référence

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

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

Et la sortie deviendra:

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

, cette fois, le tableau a été adopté « par référence ».


Ne hésitez pas à lire le du manuel: il doit répondre certaines de vos questions; -)

Autres conseils

En ce qui concerne votre première question, le tableau est passé par référence est modifié à moins qu'il dans la méthode / fonction que vous appelez. Si vous essayez de modifier le tableau dans la méthode / fonction, une copie est faite d'abord, puis seule la copie est modifiée. Cela fait croire que si le tableau est passé par valeur alors qu'en réalité il n'est pas.

Par exemple, dans ce premier cas, même si vous n'êtes pas en train de définir votre fonction d'accepter my_array $ par référence (en utilisant le caractère & dans la définition des paramètres), il obtient toujours passé par référence (ex: vous n » t la mémoire de déchets avec une copie inutile).

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 modifiez le tableau, une copie est faite d'abord (qui utilise plus de mémoire, mais laisse votre tableau d'origine non affecté).

function handle_array($my_array) {

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

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

Pour votre information - ceci est connu comme "copie paresseux" ou "copy-on-write"

.

TL;DR

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

Ou ca:
- paramètre de tableau sans esperluette:passé par référence;les opérations d'écriture modifient une nouvelle copie du tableau, copie qui est créée lors de la première écriture ;
- paramètre de tableau esperluette:passé par référence;les opérations d'écriture modifient le tableau d'origine.

N'oubliez pas - PHP fait une copie de valeur au moment où tu écris au paramètre de tableau sans esperluette.C'est ce que copy-on-write moyens.J'aimerais vous montrer la source C de ce comportement, mais c'est effrayant là-dedans.Meilleure utilisation xdebug_debug_zval().

Pascal MARTIN avait raison.Kosta Kontos l’était encore plus.

Répondre

Ça dépend.

Version longue

Je pense que j'écris ceci pour moi-même.Je devrais avoir un blog ou quelque chose comme ça...

Chaque fois que les gens parlent de références (ou d’indicateurs, d’ailleurs), ils aboutissent généralement à une logomachie (il suffit de regarder ceci). fil!).
PHP étant un langage vénérable, j'ai pensé que je devrais ajouter à la confusion (même s'il s'agit d'un résumé des réponses ci-dessus).Parce que, même si deux personnes peuvent avoir raison en même temps, il vaut mieux se contenter de se rassembler pour obtenir une seule réponse.

Tout d'abord, tu dois savoir que tu n'es pas un pédant si tu ne réponds pas en noir et blanc.Les choses sont plus compliquées que le « oui/non ».

Comme vous le verrez, toute la question par valeur/par référence est très liée à ce que vous faites exactement avec ce tableau dans la portée de votre méthode/fonction :le lire ou le modifier ?

Que dit PHP ?(alias "en termes de changement")

Le manuel dit ceci (c'est moi qui souligne) :

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

Pour avoir un argument à une fonction toujours adoptée par référence, appliquez un ampère et) au nom de l'argument dans la définition de la fonction

Autant que je sache, lorsque de grands programmeurs sérieux et honnêtes envers Dieu parlent de références, ils parlent généralement de modifier la valeur de cette référence.Et c'est exactement ce dont parle le manuel : hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value".

Il y a cependant un autre cas qu'ils ne mentionnent pas :et si je ne change rien, je lis juste ?
Que se passe-t-il si vous transmettez un tableau à une méthode qui ne marque pas explicitement de référence et que nous ne modifions pas ce tableau dans la portée de la fonction ?Par exemple.:

<?php
function readAndDoStuffWithAnArray($array) 
{
    return $array[0] + $array[1] + $array[2];
}

$x = array(1, 2, 3);

echo readAndDoStuffWithAnArray($x);

Continuez à lire, mon compagnon de voyage.

Que fait réellement PHP ?(alias "en termes de mémoire")

Les mêmes grands et sérieux programmeurs, quand ils deviennent encore plus sérieux, parlent d'"optimisations de mémoire" en ce qui concerne les références.PHP aussi.Parce que PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting, c'est pourquoi.

Il ne serait pas idéal de transmettre des tableaux ÉNORMES à diverses fonctions, et PHP d'en faire des copies (c'est ce que fait le "passage par valeur", après tout) :

<?php

// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from your 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 une transmission par valeur, nous aurions perdu plus de 3 Mo de RAM, car il y a deux des copies de ce tableau, n'est-ce pas ?

Faux.Tant que nous ne changeons pas le $arr variable, c'est une référence, au niveau de la mémoire.Vous ne le voyez tout simplement pas.C'est pourquoi PHP mentionne terrain utilisateur les références quand on parle de &$someVar, pour faire la distinction entre les internes et les explicites (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 (ouais, trois) cas :
a) la méthode/fonction lit seulement l'argument du tableau
b) la méthode/fonction modifie l'argument du tableau
c) l'argument du tableau méthode/fonction est explicitement marqué comme référence (avec une esperluette)


Tout d’abord, voyons combien de mémoire ce tableau consomme réellement (exécutez ici):

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

Autant d'octets.Super.

a) la méthode/fonction lit seulement l'argument du tableau

Créons maintenant une fonction qui lit seulement le dit tableau comme argument et nous verrons combien de mémoire prend la logique de lecture :

<?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);

Tu veux deviner ?J'en ai 80 ! Voir par vous-même.C'est la partie que le manuel PHP omet.Si la $arr param était en fait transmis par valeur, vous verriez quelque chose de similaire à 1331840 octets.Il paraît que $arr se comporte comme une référence, n'est-ce pas ?C'est parce que c'est est une référence - une référence interne.

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

Maintenant, allons écrire à ce paramètre, au lieu de le 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, voir par vous-même, mais, pour moi, c'est assez proche de 1331840.Donc dans ce cas, le tableau est en train d'être copié vers $arr.

c) l'argument du tableau méthode/fonction est explicitement marqué comme référence (avec une esperluette)

Voyons maintenant combien de mémoire une opération d'écriture sur une référence explicite prend (courir ici) - notez l'esperluette dans 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);

Je parie que vous en obtenez 200 maximum !Cela consomme donc à peu près autant de mémoire que lecture à partir d'un paramètre non-esperluette.

Par défaut

  1. Primitives sont passés par valeur. Peu susceptible de Java, la chaîne est primitive en PHP
  2. Les tableaux de primitives sont passés par valeur
  3. Les objets sont passés par référence
  4. tableaux d'objets sont passés par valeur (la matrice) mais chaque objet est passé par référence.

    <?php
    $obj=new stdClass();
    $obj->field='world';
    
    $original=array($obj);
    
    
    function example($hello) {
        $hello[0]->field='mundo'; // change will be applied in $original
        $hello[1]=new stdClass(); // change will not be applied in $original
        $
    }
    
    example($original);
    
    var_dump($original);
    // array(1) { [0]=> object(stdClass)#1 (1) { ["field"]=> string(5) "mundo" } } 
    

Remarque: À titre d'optimisation, chaque valeur unique est passée en référence jusqu'à sa modification dans la fonction. Si elle est modifiée et la valeur a été adoptée par référence puis, il est copié et la copie est modifiée.

Quand un tableau est passé à une méthode ou une fonction en PHP, il est passé par valeur à moins que vous passez explicitement par référence, comme suit:

function test(&$array) {
    $array['new'] = 'hey';
}

$a = $array(1,2,3);
// prints [0=>1,1=>2,2=>3]
var_dump($a);
test($a);
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);

Dans votre deuxième question, $b n'est pas une référence à $a, mais une copie de $a.

Tout comme le premier exemple, vous pouvez faire référence $a en procédant comme suit:

$a = array(1,2,3);
$b = &$a;
// prints [0=>1,1=>2,2=>3]
var_dump($b);
$b['new'] = 'hey';
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);

Ce fil est un peu plus mais voici quelque chose que je suis tombé sur:

Essayez ce code:

$date = new DateTime();
$arr = ['date' => $date];

echo $date->format('Ymd') . '<br>';
mytest($arr);
echo $date->format('Ymd') . '<br>';

function mytest($params = []) {
    if (isset($params['date'])) {
        $params['date']->add(new DateInterval('P1D'));
    }
}

http://codepad.viper-7.com/gwPYMw

Notez qu'il n'y a pas Ampères pour le paramètre $ params et encore change la valeur de $ arr [ « date »]. Cela ne correspond pas vraiment avec toutes les autres explications ici et ce que je pensais jusqu'à présent.

Si je clone les $ params [ 'date'] objet, 2ème jour reste le même en sortie. Si je l'ai juste mis à une chaîne, il n'a pas d'effet la sortie soit.

Dans les tableaux PHP sont passés aux fonctions par la valeur par défaut, à moins que vous les transmettre explicitement référence, comme l'indique le code suivant:

$foo = array(11, 22, 33);

function hello($fooarg) {
  $fooarg[0] = 99;
}

function world(&$fooarg) {
  $fooarg[0] = 66;
}

hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value

world($foo);
var_dump($foo); // (original array modified) array passed-by-reference

Voici la sortie:

array(3) {
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
}
array(3) {
  [0]=>
  int(66)
  [1]=>
  int(22)
  [2]=>
  int(33)
}

Pour prolonger l'une des réponses, également des sous-tableaux tableaux multidimensionnels sont passés par valeur qu'elle ne soit adoptée par référence explicitement.

<?php
$foo = array( array(1,2,3), 22, 33);

function hello($fooarg) {
  $fooarg[0][0] = 99;
}

function world(&$fooarg) {
  $fooarg[0][0] = 66;
}

hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value

world($foo);
var_dump($foo); // (original array modified) array passed-by-reference

Le résultat est:

array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}
array(3) {
  [0]=>
  array(3) {
    [0]=>
    int(66)
    [1]=>
    int(2)
    [2]=>
    int(3)
  }
  [1]=>
  int(22)
  [2]=>
  int(33)
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top