Maison > Article > interface Web > Explication détaillée de l'utilisation de la liaison statique PHP
Cette fois, je vais vous apporter une explication détaillée de l'utilisation de la liaison statique PHP. Quelles sont les précautions à prendre pour utiliser la liaison statique PHP ? Ce qui suit est un cas pratique, jetons un coup d'œil.
Connaissances de base
1. L'opérateur d'analyse de plage (::)
peut être utilisé. Il est utilisé pour accéder aux membres statiques et aux constantes de classe, et peut également être utilisé pour remplacer les propriétés et méthodes dans la classe.
Les trois mots-clés spéciaux self, parent et static sont utilisés pour accéder à ses propriétés ou méthodes à l'intérieur de la définition de classe.
parent est utilisé pour appeler des propriétés ou des méthodes remplacées dans la classe parent (là où il apparaît, il sera résolu en classe parent de la classe correspondante).
self est utilisé pour appeler des méthodes ou des propriétés dans cette classe (partout où il apparaît, il sera analysé dans la classe correspondante ; notez la différence avec $this, $this pointe vers l'actuel objet instancié).
Lorsqu'une sous-classe substitue une méthode dans sa classe parent, PHP n'appellera pas la méthode substituée dans la classe parent. L’appel de la méthode de la classe parent dépend de la classe enfant.
2. Le noyau PHP place l'implémentation de l'héritage des classes dans la "phase de compilation"
<?php class A{ const H = 'A'; const J = 'A'; static function testSelf(){ echo self::H; //在编译阶段就确定了 self解析为 A } } class B extends A{ const H = "B"; const J = 'B'; static function testParent(){ echo parent::J; //在编译阶段就确定了 parent解析为A } /* 若重写testSelf则能输出“B”, 且C::testSelf()也是输出“B” static function testSelf(){ echo self::H; } */ } class C extends B{ const H = "C"; const J = 'C'; } B::testParent(); B::testSelf(); echo "\n"; C::testParent(); C::testSelf();
Résultats d'exécution :
AA
AA
Conclusion :
self:: et parent:: apparaissent dans la définition d'une certaine classe Classe X, à moins que la méthode de la classe parent est remplacée dans la sous-classe.
3.Mot-clé statique (statique)
Fonction :
- clé statique pour les variables modifiées dans le corps de la fonction Le le mot est utilisé pour définir des variables locales statiques.
- Utilisé pour déclarer des membres statiques lors de la modification des fonctions membres de la classe et des variables membres.
- (après PHP5.3) une classe spéciale qui représente la liaison statique retardée avant le résolveur de portée (::).
Exemple :
Définir des variables locales statiques (occurrence : dans les fonctions locales)
Fonctionnalité : Les variables statiques n'existent que dans le domaine de la fonction locale, mais lorsque le programme Lorsque l’exécution quitte ce périmètre, sa valeur n’est pas perdue.
<?php function test() { static $count = 0; $count++; echo $count; if ($count < 10) { test(); } $count--; }
Définir les méthodes statiques et les attributs statiques
a) Déclarez les attributs ou les méthodes de classe comme statiques, afin qu'ils soient accessibles directement sans instancier la classe.
b) Les propriétés statiques ne sont pas accessibles via un objet instancié d'une classe (mais les méthodes statiques le peuvent)
c) Si aucun contrôle d'accès n'est spécifié, les propriétés et les méthodes La valeur par défaut est publique.
d) Étant donné que les méthodes statiques ne nécessitent pas l'appel d'un objet, la pseudo variable $this n'est pas disponible dans les méthodes statiques.
e) Les propriétés statiques ne sont pas accessibles aux objets via l'opérateur ->
f) L'appel statique d'une méthode non statique entraînera une erreur de niveau E_STRICT.
g) Comme toutes les autres variables statiques PHP, les propriétés statiques ne peuvent être initialisées qu'avec des littéraux ou des constantes, pas des expressions. Ainsi, une propriété statique peut être initialisée avec un entier ou un tableau, mais elle ne peut pas être initialisée avec une autre valeur de retour de variable ou de fonction, ni pointer vers un objet.
a. Exemple de méthode statique (emplacement d'apparence : définition de la méthode de classe)
<?php class Foo { public static function aStaticMethod() { // ... } } Foo::aStaticMethod(); $classname = 'Foo'; $classname::aStaticMethod(); // 自PHP 5.3.0后,可以通过变量引用类 ?>
b. Exemple d'attribut statique (emplacement d'apparence : définition de l'attribut de classe)
<?php class Foo { public static $my_static = 'foo'; public function staticValue() { return self::$my_static; //self 即 FOO类 } } class Bar extends Foo { public function fooStatic() { return parent::$my_static; //parent 即 FOO类 } } print Foo::$my_static . "\n"; $foo = new Foo(); print $foo->staticValue() . "\n"; print $foo->my_static . "\n"; // Undefined "Property" my_static print $foo::$my_static . "\n"; $classname = 'Foo'; print $classname::$my_static . "\n"; // As of PHP 5.3.0 print Bar::$my_static . "\n"; $bar = new Bar(); print $bar->fooStatic() . "\n"; ?>
c. Utilisé pour liaison statique tardive (position : dans une méthode de classe, utilisée pour modifier des variables ou des méthodes)
Analyse détaillée ci-dessous
Tardive. liaison statique
Depuis PHP 5.3.0, PHP a ajouté une fonctionnalité appelée liaison statique tardive, qui est utilisée pour référencer des classes appelées statiquement dans la portée de l'héritage.
1. Appels renvoyés et appels non renvoyés
Appels renvoyés :
fait référence aux appels statiques passés des manières suivantes : soi-même : :, parent ::, static :: et forward_static_call().
Appels non transférés :
Appels statiques qui spécifient explicitement le nom de la classe (par exemple Foo::foo())
Appels non statiques (par exemple $foo-> ;foo())
2. Principe de fonctionnement de la liaison statique tardive
原理:存储了在上一个“非转发调用”(non-forwarding call)中的类名。意思是当我们调用一个转发调用的静态调用时,实际调用的类是上一个非转发调用的类。
例子分析:
<?php class A { public static function foo() { echo CLASS."\n"; static::who(); } public static function who() { echo CLASS."\n"; } } class B extends A { public static function test() { echo "A::foo()\n"; A::foo(); echo "parent::foo()\n"; parent::foo(); echo "self::foo()\n"; self::foo(); } public static function who() { echo CLASS."\n"; } } class C extends B { public static function who() { echo CLASS."\n"; } } C::test(); /* * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C * * //当前的“上一次非转发调用”存储的类名为C * public static function test() { * A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0 * parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0 * self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0 * } * * * 0-0 * //当前的“上一次非转发调用”存储的类名为A * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A” * } * * 1-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } * * 2-0 * //当前的“上一次非转发调用”存储的类名为C * public static function foo() { * static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C” * } */ 故最终结果为: A::foo() A A parent::foo() A C self::foo() A C
3.更多静态后期静态绑定的例子
a)Self, Parent 和 Static的对比
<?php class Mango { function classname(){ return CLASS; } function selfname(){ return self::classname(); } function staticname(){ return static::classname(); } } class Orange extends Mango { function parentname(){ return parent::classname(); } function classname(){ return CLASS; } } class Apple extends Orange { function parentname(){ return parent::classname(); } function classname(){ return CLASS; } } $apple = new Apple(); echo $apple->selfname() . "\n"; echo $apple->parentname() . "\n"; echo $apple->staticname(); ?> 运行结果: Mango Orange Apple
b)使用forward_static_call()
<?php class Mango { const NAME = 'Mango is'; public static function fruit() { $args = func_get_args(); echo static::NAME, " " . join(' ', $args) . "\n"; } } class Orange extends Mango { const NAME = 'Orange is'; public static function fruit() { echo self::NAME, "\n"; forward_static_call(array('Mango', 'fruit'), 'my', 'favorite', 'fruit'); forward_static_call('fruit', 'my', 'father\'s', 'favorite', 'fruit'); } } Orange::fruit('NO'); function fruit() { $args = func_get_args(); echo "Apple is " . join(' ', $args). "\n"; } ?> 运行结果: Orange is Orange is my favorite fruit Apple is my father's favorite fruit
c)使用get_called_class()
<?php class Mango { static public function fruit() { echo get_called_class() . "\n"; } } class Orange extends Mango { // } Mango::fruit(); Orange::fruit(); ?> 运行结果: Mango Orange
应用
前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以, 可以用后期静态绑定的办法解决单例继承问题。
先看一下使用self是一个什么样的情况:
<?php // new self 得到的单例都为A。 class A { protected static $_instance = null; protected function construct() { //disallow new instance } protected function clone(){ //disallow clone } static public function getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; } } class B extends A { protected static $_instance = null; } class C extends A{ protected static $_instance = null; } $a = A::getInstance(); $b = B::getInstance(); $c = C::getInstance(); var_dump($a); var_dump($b); var_dump($c); 运行结果: E:\code\php_test\apply\self.php:37: class A#1 (0) { } E:\code\php_test\apply\self.php:38: class A#1 (0) { } E:\code\php_test\apply\self.php:39: class A#1 (0) { }
通过上面的例子可以看到,使用self,实例化得到的都是类A的同一个对象
再来看看使用static会得到什么样的结果
<?php // new static 得到的单例分别为D,E和F。 class D { protected static $_instance = null; protected function construct(){} protected function clone() { //disallow clone } static public function getInstance() { if (static::$_instance === null) { static::$_instance = new static(); } return static::$_instance; } } class E extends D { protected static $_instance = null; } class F extends D{ protected static $_instance = null; } $d = D::getInstance(); $e = E::getInstance(); $f = F::getInstance(); var_dump($d); var_dump($e); var_dump($f); 运行结果: E:\code\php_test\apply\static.php:35: class D#1 (0) { } E:\code\php_test\apply\static.php:36: class E#2 (0) { } E:\code\php_test\apply\static.php:37: class F#3 (0) { }
相信看了本文案例你已经掌握了方法,更多精彩请关注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!