Maison >développement back-end >tutoriel php >Choses à noter à propos de __construct() et __destory() en PHP
Fondamentalement, tous les langages de programmation ont les concepts de constructeurs et de destructeurs dans les classes. Le constructeur peut être utilisé pour effectuer un travail d'initialisation lorsqu'une instance de fonction est créée, tandis que le destructeur peut effectuer un travail de nettoyage avant la destruction de l'instance. Relativement parlant, nous utilisons beaucoup les constructeurs, tandis que les destructeurs sont généralement utilisés pour libérer des ressources, telles que des liens de bases de données, des handles de lecture et d'écriture de fichiers, etc.
L'utilisation des constructeurs et des destructeurs
Regardons d'abord l'utilisation des constructeurs et des destructeurs normaux :
class A { public $name; public function __construct($name) { $this->name = $name; echo "A:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { echo "A:析构函数被调用,{$this->name}", PHP_EOL; } } $a = new A('$a'); echo '-----', PHP_EOL; class B extends A { public function __construct($name) { $this->name = $name; parent::__construct($name); echo "B:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { parent::__destruct(); echo "B:析构函数被调用,{$this->name}", PHP_EOL; } } class C extends A { public function __construct($name) { $this->name = $name; echo "C:构造函数被调用,{$this->name}", PHP_EOL; } public function __destruct() { echo "C:析构函数被调用,{$this->name}", PHP_EOL; } } class D extends A { } // unset($a); // $a的析构提前 // $a = null; // $a的析构提前 $b = new B('$b'); $c = new C('$c'); $d = new D('$d'); echo '-----', PHP_EOL;exit; // A:构造函数被调用,$a // ----- // A:构造函数被调用,$b // B:构造函数被调用,$b // C:构造函数被调用,$c // A:构造函数被调用,$d // ----- // A:析构函数被调用,$d // C:析构函数被调用,$c // A:析构函数被调用,$b // B:析构函数被调用,$b // A:析构函数被调用,$a
Ce qui précède Y a-t-il quelque chose dans le un code différent de ce à quoi nous nous attendions ? C'est bon, regardons ça un par un :
Si une sous-classe remplace le constructeur ou le destructeur de la classe parent, et si le constructeur de la classe parent n'est pas explicitement appelé en utilisant parent::__constuct(), alors le la classe parent Le constructeur de la classe ne sera pas exécuté.Par exemple, si une sous-classe de la classe C ne remplace pas le constructeur ou le destructeur, le destructeur de la classe parent sera appelé par défaut si la variable n'est pas explicitement définie sur. NULL ou unset() est utilisé, il sera appelé une fois l'exécution du script terminée. L'ordre d'appel dans le code de test est similaire à la pile premier entré dernier sorti (C->B->A, C est détruit. premier), mais dans l'environnement serveur ce n'est pas forcément le cas. C'est à dire que l'ordre n'est pas forcément fixé
Problème de référence du destructeur
Quand les objets contiennent des références mutuelles à eux-mêmes, vous souhaitez le définir sur NULL ou unset() peut causer des problèmes lors de l'appel du destructeur.
class E { public $name; public $obj; public function __destruct() { echo "E:析构函数被调用," . $this->name, PHP_EOL; echo '-----', PHP_EOL; } } $e1 = new E(); $e1->name = 'e1'; $e2 = new E(); $e2->name = 'e2'; $e1->obj = $e2; $e2->obj = $e1;
Semblable à ce code, $e1 et $e2 sont tous deux des objets de classe E, et ils contiennent chacun des références l'un à l'autre. En fait, pour faire simple, des problèmes similaires surgiront si vous détenez vos propres références.
$e1 = new E(); $e1->name = 'e1'; $e2 = new E(); $e2->name = 'e2'; $e1->obj = $e2; $e2->obj = $e1; $e1 = null; $e2 = null; // gc_collect_cycles(); $e3 = new E(); $e3->name = 'e3'; $e4 = new E(); $e4->name = 'e4'; $e3->obj = $e4; $e4->obj = $e3; $e3 = null; $e4 = null; echo 'E destory', PHP_EOL;
Si on n'active pas le commentaire sur la ligne gc_collect_cycles(), l'ordre dans lequel le destructeur est exécuté est le suivant :
// 不使用gc回收的结果 // E destory // E:析构函数被调用,e1 // ----- // E:析构函数被调用,e2 // ----- // E:析构函数被调用,e3 // ----- // E:析构函数被调用,e4 // -----
Si on active le commentaire sur gc_collect_cycles( ), l'ordre d'exécution du destructeur est :
// 使用gc回收后结果 // E:析构函数被调用,e1 // ----- // E:析构函数被调用,e2 // ----- // E destory // E:析构函数被调用,e3 // ----- // E:析构函数被调用,e4 // -----
On voit que PHP doit être recyclé une fois en utilisant gc, et le destructeur de la classe ne sera exécuté que lorsque toutes les références à l'objet seront libérées. Si la référence n'est pas libérée, le destructeur ne sera pas exécuté.
Problèmes de compatibilité avec les constructeurs de versions basses
Avant PHP5, le constructeur de PHP était une méthode portant le même nom que le nom de la classe. C'est-à-dire que si j'ai une classe F, alors la méthode function F(){} est son constructeur. Afin d'être compatible avec les versions inférieures, PHP conserve toujours cette fonctionnalité. Après PHP7, s'il existe une méthode portant le même nom que le nom de la classe, un avertissement de délai d'attente sera signalé, mais cela n'affectera pas l'exécution du programme.
class F { public function f() { // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor echo "F:这也是构造函数,与类同名,不区分大小写", PHP_EOL; } // function F(){ // // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor // echo "F:这也是构造函数,与类同名", PHP_EOL; // } // function __construct(){ // echo "F:这是构造函数,__construct()", PHP_EOL; // } } $f = new F();
Si __construc() et une méthode de classe du même nom existent en même temps, __construct() sera utilisée en premier. Une autre chose à noter est que les noms de fonctions ne sont pas sensibles à la casse, donc les méthodes F() et f() sont les mêmes et deviendront des constructeurs. De même, comme ils ne sont pas sensibles à la casse, f() et F() ne peuvent pas exister en même temps. Bien entendu, nous vous déconseillons d'utiliser une fonction du même nom qu'un constructeur. Après tout, il s'agit d'une fonctionnalité obsolète et qui pourrait être annulée un jour.
Surcharge de constructeur
PHP n'exécute pas la surcharge de méthodes. Il prend uniquement en charge la réécriture, c'est-à-dire que les sous-classes remplacent les méthodes de la classe parent, mais ne peut pas définir plusieurs méthodes avec le. même nom mais paramètres différents. Dans des langages comme Java, la surcharge de méthodes est très pratique, notamment lors de l'instanciation d'une classe, pour implémenter facilement des capacités polymorphes.
$r1 = new R(); // 默认构造函数 $r2 = new R('arg1'); // 默认构造函数 一个参数的构造函数重载,arg1 $r3 = new R('arg1', 'arg2'); // 默认构造函数 两个参数的构造函数重载,arg1,arg2
Tout comme le code ci-dessus, si vous essayez de définir plusieurs __construct(), PHP vous dira directement qu'il ne peut pas s'exécuter. Existe-t-il donc un autre moyen d’obtenir la fonction du code ci-dessus ? Bien sûr qu’il y en a, sinon nous ne l’écririons pas.
class R { private $a; private $b; public function __construct() { echo '默认构造函数', PHP_EOL; $argNums = func_num_args(); $args = func_get_args(); if ($argNums == 1) { $this->constructA(...$args); } elseif ($argNums == 2) { $this->constructB(...$args); } } public function constructA($a) { echo '一个参数的构造函数重载,' . $a, PHP_EOL; $this->a = $a; } public function constructB($a, $b) { echo '两个参数的构造函数重载,' . $a . ',' . $b, PHP_EOL; $this->a = $a; $this->b = $b; } } $r1 = new R(); // 默认构造函数 $r2 = new R('arg1'); // 默认构造函数 一个参数的构造函数重载,arg1 $r3 = new R('arg1', 'arg2'); // 默认构造函数 两个参数的构造函数重载,arg1,arg2
C'est relativement plus gênant que des langages comme Java, mais il remplit la même fonction.
Restrictions d'accès aux constructeurs et destructeurs
Les constructeurs et les destructeurs sont publics par défaut et ont les mêmes valeurs par défaut que les autres méthodes de la classe. Bien entendu, ils peuvent également être définis comme privés et protégés. Si vous rendez le constructeur non public, vous ne pourrez pas instancier la classe. Ceci est largement utilisé dans le mode singleton. Regardons directement le code d'un mode singleton.
class Singleton { private static $instance; public static function getInstance() { return self::$instance == null ? self::$instance = new Singleton() : self::$instance; } private function __construct() { } } $s1 = Singleton::getInstance(); $s2 = Singleton::getInstance(); echo $s1 === $s2 ? 's1 === s2' : 's1 !== s2', PHP_EOL; // $s3 = new Singleton(); // Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context
Lorsque $s3 veut être instancié, une erreur est directement signalée. Concernant la question de savoir pourquoi le modèle singleton rend impossible l'instanciation en externe, nous pouvons examiner le modèle singleton dans l'article précédent sur le système de modèles de conception.
Résumé
Je ne m'attendais pas à ce que le constructeur que nous utilisons chaque jour puisse avoir autant d'astuces. Ce à quoi il faut prêter attention dans le développement quotidien, c'est l'héritage des sous-classes. . Le problème est le problème d'appel du constructeur de la classe parent lorsque le constructeur est remplacé et le problème de destruction lorsque la référence est faite.
Tutoriel recommandé : "Tutoriel 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!