Maison >développement back-end >Problème PHP >Que signifie le comptage de références en PHP ?

Que signifie le comptage de références en PHP ?

醉折花枝作酒筹
醉折花枝作酒筹avant
2021-05-08 17:31:401809parcourir

Cet article vous présentera le comptage de références PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

Que signifie le comptage de références en PHP ?

Qu'est-ce que le comptage de références

Dans la structure de données PHP, le comptage de références fait référence à chaque variable, en plus de stocker leur type et leur valeur, et enregistre également deux contenu supplémentaire, l'un est de savoir si la variable est actuellement référencée et l'autre est le nombre de références. Pourquoi devons-nous sauvegarder deux contenus supplémentaires ? Pour le garbage collection (GC) bien sûr.

C'est-à-dire que lorsque le nombre de références est égal à 0, cette variable n'est plus utilisée et peut être recyclée via GC pour libérer les ressources mémoire occupées.

Aucun programme ne peut occuper indéfiniment les ressources mémoire. Une utilisation excessive de la mémoire entraîne souvent un problème grave, c'est-à-dire des fuites de mémoire, et GC est la couche inférieure de PHP qui termine automatiquement le traitement de la mémoire pour nous. de devoir libérer manuellement comme C.

Comment vérifier le décompte des références ?

Nous devons installer l'extension xdebug, puis utiliser la fonction xdebug_debug_zval() pour voir les informations détaillées de la mémoire spécifiée, telles que :

$a = "I am a String";
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'

Comme le montre ce qui précède, this $a variable Le contenu est une chaîne comme je suis une chaîne. Le refcount entre parenthèses est le nombre de références et is_ref indique si la variable est référencée. Voyons comment ces deux paramètres changent grâce à l'affectation de variables.

$b = $a;
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=0)='I am a String'

$b = &$a;
xdebug_debug_zval('a');
// a: (refcount=2, is_ref=1)='I am a String'

Lorsque nous effectuons une affectation normale, refcount et is_ref ne changent pas du tout, mais lorsque nous effectuons une affectation de référence, nous pouvons voir que refcount devient 2 et is_ref devient 1. Cela signifie que la variable $a actuelle est affectée par référence et que sa table de symboles de mémoire sert les deux variables $a et $b.

$c = &$a;
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String'

unset($c, $b);
xdebug_debug_zval('a');
// a: (refcount=1, is_ref=1)='I am a String'

$b = &$a;
$c = &$a;
$b = "I am a String new";
xdebug_debug_zval('a');
// a: (refcount=3, is_ref=1)='I am a String new'

unset($a);
xdebug_debug_zval('a');
// a: no such symbol

Continuez à ajouter une affectation de référence à $c, et vous pouvez voir que le refcount continuera d'augmenter. Puis après avoir annulé $b et $c, refcount revient à 1. Cependant, il convient de noter que is_ref vaut toujours 1. C'est-à-dire que si cette variable a été référencée, is_ref deviendra 1, même si la variable référencée Even si elle n'a pas été définie, la valeur reste inchangée.

Enfin, nous désactivons $a et le message affiché n'est pas un tel symbole. La variable actuelle a été détruite et n'est plus une référence symbolique utilisable. (Notez que les variables en PHP correspondent à la table des symboles de la mémoire, pas à la véritable adresse mémoire)

Le nombre de références de l'objet

est le même que le type ordinaire de variables, et le les variables d'objet sont également utilisées de la même manière.

// 对象引用计数
class A{

}
$objA = new A();
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }

$objB = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=2, is_ref=0)=class A {  }

$objC = $objA;
xdebug_debug_zval('objA');
// objA: (refcount=3, is_ref=0)=class A {  }

unset($objB);
class C{

}
$objC = new C;
xdebug_debug_zval('objA');
// objA: (refcount=1, is_ref=0)=class A {  }

Cependant, il convient de noter ici que la table des symboles de l'objet est une connexion établie. En d'autres termes, la ré-instanciation ou la modification de $objC en NULL n'affectera pas le contenu de $objA. concernant Connaissance : notre affectation d'objet précédente est-elle une référence en PHP ? Cela a été expliqué dans l'article. Les opérations d'affectation ordinaires sur les objets sont également des affectations de tables de symboles de types référence, nous n'avons donc pas besoin d'ajouter le symbole &.

Comptage de références des tableaux

// 数组引用计数
$arrA = [
    'a'=>1,
    'b'=>2,
];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

$arrB = $arrA;
$arrC = $arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=4, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

unset($arrB);
$arrC = ['c'=>3];
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=0)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2
// )

// 添加一个已经存在的元素
$arrA['c'] = &$arrA['a'];
xdebug_debug_zval('arrA');
// arrA: (refcount=1, is_ref=0)=array (
//     'a' => (refcount=2, is_ref=1)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'c' => (refcount=2, is_ref=1)=1
// )

Lors du débogage des tableaux, nous trouverons deux choses intéressantes.

Tout d'abord, chaque élément à l'intérieur du tableau a son propre nombre de références distinct. Ceci est également plus facile à comprendre. Chaque élément du tableau peut être considéré comme une variable distincte, mais le tableau est un ensemble de hachage de ces variables. S'il y a des variables membres dans l'objet, le même effet se produira. Lorsqu'un élément du tableau est affecté à une autre variable par &, le refcount de cet élément sera augmenté sans affecter le refcount de l'ensemble du tableau.

Deuxièmement, le refcount par défaut du tableau est 2. En fait, il s'agit d'une nouvelle fonctionnalité après PHP7. Lorsqu'un tableau est défini et initialisé, il sera converti en un tableau immuable (immuable array). Afin de le distinguer des tableaux ordinaires, le refcount de ce tableau commence à 2. Lorsque nous modifions un élément de ce tableau, le tableau redeviendra un tableau normal, c'est-à-dire que refcount reviendra à 1. Vous pouvez essayer cela vous-même. Quant à la raison pour laquelle cela est fait, l'explication officielle est l'efficacité. Le principe spécifique devra peut-être encore être approfondi dans le code source de PHP7 pour le savoir.

Choses à noter concernant les fuites de mémoire

En fait, PHP nous a déjà aidé avec le mécanisme GC au niveau inférieur, nous n'avons donc pas à nous soucier trop de la destruction et de la libération de variables. Cependant, nous devons faire attention à cela. Les éléments d'un objet ou d'un tableau peuvent être assignés à eux-mêmes, c'est-à-dire que l'attribution d'une référence à lui-même à un élément devient une référence circulaire. Il est alors fondamentalement peu probable que cet objet soit automatiquement détruit par GC.

// 对象循环引用
class D{
    public $d;
}
$d = new D;
$d->d = $d;
xdebug_debug_zval('d');
// d: (refcount=2, is_ref=0)=class D { 
//     public $d = (refcount=2, is_ref=0)=... 
// }

// 数组循环引用
$arrA['arrA'] = &$arrA;
xdebug_debug_zval('arrA');
// arrA: (refcount=2, is_ref=1)=array (
//     'a' => (refcount=0, is_ref=0)=1, 
//     'b' => (refcount=0, is_ref=0)=2, 
//     'arrA' => (refcount=2, is_ref=1)=...
// )

Qu'il s'agisse d'un objet ou d'un tableau, si des points de suspension comme... apparaissent lors de l'impression et du débogage, alors il y aura une référence circulaire dans votre programme. Dans l'article précédent sur la copie d'objets en PHP, nous avons également parlé de ce problème de référence circulaire, ce problème devrait donc être un sujet auquel nous devons toujours prêter attention dans le développement quotidien.

Apprentissage recommandé : Tutoriel vidéo php

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer