Introduction aux objets et références en mémoire PHP

Publié: 2022-03-11

J'ai d'abord rédigé cet article alors que j'étudiais pour ma certification PHP dans le but de mieux comprendre comment PHP gère les variables et les objets en mémoire. Après de nombreuses recherches, je me suis rendu compte qu'il n'était pas facile de trouver des réponses à mes questions, alors une fois que j'ai eu fini, j'ai décidé de documenter l'information afin que les gens puissent tout trouver au même endroit.

Dans cet article, je parlerai de la façon dont les références d'objets et de variables sont contrôlées en mémoire, car il s'agit d'un problème qui peut générer des discussions et des opinions divergentes. Une question à se poser est : « Par défaut, les objets sont-ils passés par référence ou par copie en PHP ? Je vais d'abord parler des références qui ne sont pas en PHP ; deuxièmement, je discuterai de ce qu'ils sont , et enfin, j'examinerai comment fonctionne le ramasse-miettes en PHP.

Comment PHP crée-t-il des objets en mémoire lors de l'exécution d'une instruction telle que $a = new Foo(); ? De nos jours, la mémoire n'est pas une ressource aussi chère et limitée qu'elle l'était par le passé. Cependant, il est toujours important pour les bons développeurs PHP de savoir et de comprendre comment les variables et les objets sont gérés en interne lors de l'exécution de leur application.

Objets et références dans la mémoire PHP et la récupération de place PHP

Objets et références en PHP

Beaucoup de gens disent - dans les livres PHP et en ligne - que les objets en PHP sont passés par référence par défaut. D'autres disent que les objets en PHP sont alloués par copie. Pour déterminer quelle déclaration est correcte, nous devons d'abord analyser ce qui est (et ce qui n'est pas) une référence en PHP.

Qu'est-ce qui ne sont pas des références en PHP ?

Plus important que de savoir quelles sont les références en PHP, c'est de savoir ce qu'elles ne sont pas . En PHP, les références ne sont pas des pointeurs de style C ; vous ne pouvez pas faire d'opérations arithmétiques avec des références comme vous le pouvez avec des pointeurs C. Pourquoi? Car, contrairement au C, les références PHP ne sont pas vraiment des adresses mémoire, puisque ce ne sont pas des nombres indiquant un emplacement mémoire. Mais alors, quelles sont les références ?

Que sont les références en PHP ?

En PHP, les références sont des « alias » qui permettent à deux variables différentes de lire et d'écrire une seule valeur. En d'autres termes, ce sont des mécanismes qui permettent d'accéder à la même valeur à partir de variables portant des noms différents afin qu'elles se comportent comme s'il s'agissait de la même variable. Gardez à l'esprit qu'en PHP, les noms de variables et le contenu des variables sont deux choses totalement différentes, liées dans ce qu'on appelle la "table des symboles". Ainsi, lorsque nous créons une référence, elle ajoute simplement un alias pour cette variable dans la table des symboles. Supposons que nous ayons le code suivant :

 $a = new Foo();

Lorsque l'instruction ci-dessus est exécutée, la variable $a est créée en mémoire, un objet de type Foo est créé en mémoire et une entrée est ajoutée à la table des symboles qui indique que la variable $a "fait référence" (ou est liée à , ou pointe vers, ou appelez-le comme vous voulez) l'objet Foo , mais ce n'est pas un pointeur vers cet objet en soi. Conceptuellement, nous avons quelque chose comme cette illustration :

Références d'objet dans la mémoire PHP

Quiz pop : que se passe-t-il si nous exécutons ceci ?

 $b = $a;

Ce n'est pas que $b devienne une référence de $a ; nous ne pouvons pas non plus dire que $b est une copie de $a . Ce qui s'est réellement passé, c'est que nous avons créé une nouvelle variable $b en mémoire, puis ajouté une nouvelle entrée dans la table des symboles indiquant que la variable $b fait également référence au même objet Foo que $a . Donc, visuellement, nous avons quelque chose de similaire à ce qui est montré dans cette illustration :

Références d'objet dans la mémoire PHP

Maintenant, si nous exécutons :

 $c = &$a;

Nous aurons créé une troisième variable $c en mémoire, mais pas une nouvelle entrée dans la table des symboles pour $c . Au lieu de cela, dans la table des symboles, il est enregistré que $c est un alias pour $a , donc il se comportera de manière identique, mais $c n'est pas un pointeur vers $a - contrairement à C, qui crée quelque chose appelé pointeurs vers des pointeurs . Pour visualiser, nous avons quelque chose de similaire à ce qui est montré dans cette illustration :

Diagramme des variables et de leurs alias

Dès que l'on voudra modifier la valeur de l'une de ces trois variables (c'est-à-dire écrire une nouvelle valeur), PHP devra créer une nouvelle structure z_val en mémoire pour séparer le contenu de la variable $b et du couple $a / $c afin qu'ils puissent chacun être modifiés indépendamment sans affecter la valeur de l'autre. Donc, si nous ajoutons la ligne suivante au script précédent :

 $b = new Bar();

En mémoire, nous aurons une situation telle que représentée dans l'illustration suivante :

Représentation graphique de la situation décrite ci-dessus

Prenons maintenant un exemple plus complet :

 <?php class myClass { public $var; function __construct() { $this->var = 1; } function inc() { return ++$this->var; } } $a = new myClass(); // $a "references" a Foo object $b = $a; //b also references the same Foo object as a //($a) == ($b) == <id> of Foo object, but a and b are different entries in symbols table echo "$a = ";var_dump($a); echo "$b = ";var_dump($b); $c = &$a; //$c is an alias of $a //($a, $c) == <id> of Foo object, c is an alias of a in the symbols table echo "$c = ";var_dump($c); $a = NULL; //The entry in the symbols table which links "$a" with Foo object is removed //Since that entry was removed, $c is not related to Foo anymore //Anyway, Foo still exists in memory and it is still linked by $b echo "$a = ";var_dump($a); echo "$b = ";var_dump($b); echo "$c = ";var_dump($c); echo "$b->var: ".$b->inc(); echo "$b->var: ".$b->inc(); $b = NULL; //The entry in the symbols table which links "$b" with the Foo object is removed //There are no more entries in the symbols table linked to Foo, //So, Foo is not referenced anymore and can be deleted by the garbage collector echo "$b = ";var_dump($b);

La sortie produite par l'implémentation du script ci-dessus est :

 $a = object(myClass)#1 (1) { ["var"]=> int(1) } $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = object(myClass)#1 (1) { ["var"]=> int(1) } $a = NULL $b = object(myClass)#1 (1) { ["var"]=> int(1) } $c = NULL $b->var: 2 $b->var: 3 $b = NULL

Collecte de déchets PHP

Enfin, voyons comment fonctionne le ramasse-miettes PHP, puisqu'il a été introduit dans la version 5.3. Un objet ou une variable dans la mémoire PHP sera supprimé par le ramasse-miettes PHP lorsqu'il n'y a aucune référence à cet objet dans la table des symboles. C'est-à-dire que PHP maintient un compteur de références d'un objet à partir du moment où il est créé de sorte que lors de l'exécution du script PHP, le compteur incrémente et décrémente ce compteur de référence en fonction des variables qui "pointent" vers lui. Une fois que le nombre de références atteint 0 (c'est-à-dire que rien ne fait référence à cet objet et, par conséquent, il n'est pas utilisé), PHP marque cet objet comme amovible, de sorte qu'au prochain passage du ramasse-miettes PHP, il sera supprimé de la mémoire , libérant cet espace pour une réutilisation. Si vous souhaitez plus de détails sur le fonctionnement du ramasse-miettes PHP, lisez cette documentation.

Réflexions finales

J'espère avoir un peu clarifié comment PHP gère les objets et les variables en mémoire et comment il "sélectionne" les objets qui doivent être supprimés par le ramasse-miettes PHP.

Maintenant que vous comprenez comment PHP gère les variables et les objets en mémoire en interne, prenez votre ordinateur portable et commencez à expérimenter avec du code pour prouver ce que vous avez appris. Essayez de jouer avec les variables et les références. En outre, expérimentez comment la modification de la valeur d'une variable peut affecter la valeur d'une autre qui y fait référence. Voici une question pour vous : Quelles seront les valeurs de $a et $b après l'exécution du code ci-dessous ?

 $a = '1'; $b = &$a; $b = "2$b";

Si vous souhaitez en savoir plus sur les fonctionnalités de performance de PHP, consultez cet article de Toptaler Vilson Duka.