Maison > interface Web > js tutoriel > le corps du texte

Explication détaillée de l'utilisation de l'analyse de liaison statique tardive PHP

php中世界最好的语言
Libérer: 2018-05-03 17:19:15
original
1267 Les gens l'ont consulté

Cette fois, je vous apporte une explication détaillée de l'analyse et de l'utilisation de PHP liaison statique tardive Quelles sont les précautions à prendre pour utiliser l'analyse de liaison statique tardive PHP ? Ce qui suit est un cas pratique, jetons un coup d'oeil.

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 une 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 = &#39;A&#39;;
 const J = &#39;A&#39;;
 static function testSelf(){
  echo self::H; //在编译阶段就确定了 self解析为 A
 }
}
class B extends A{
 const H = "B";
 const J = &#39;B&#39;;
 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 = &#39;C&#39;;
}
B::testParent();
B::testSelf();
echo "\n";
C::testParent();
C::testSelf();
Copier après la connexion

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) représente une classe spéciale de 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 Sa valeur n'est pas perdue lorsque l'exécution sort de ce cadre.

<?php
function test()
{
 static $count = 0;
 $count++;
 echo $count;
 if ($count < 10) {
  test();
 }
 $count--;
}
Copier après la connexion

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'apparition : définition de la méthode de classe)

<?php
class Foo {
 public static function aStaticMethod() {
  // ...
 }
}
Foo::aStaticMethod();
$classname = &#39;Foo&#39;;
$classname::aStaticMethod(); // 自PHP 5.3.0后,可以通过变量引用类
?>
Copier après la connexion

b. c. Utilisé pour la liaison statique tardive (position : dans les méthodes de classe, utilisé pour modifier des variables ou des méthodes)

<?php
class Foo
{
 public static $my_static = &#39;foo&#39;;
 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";
?>
Copier après la connexion

Analyse détaillée ci-dessous

Liaison statique tardive Liaison statique tardive

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
Copier après la connexion

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
Copier après la connexion

b)使用forward_static_call()

<?php
class Mango
{
 const NAME = &#39;Mango is&#39;;
 public static function fruit() {
  $args = func_get_args();
  echo static::NAME, " " . join(&#39; &#39;, $args) . "\n";
 }
}
class Orange extends Mango
{
 const NAME = &#39;Orange is&#39;;
 public static function fruit() {
  echo self::NAME, "\n";
  forward_static_call(array(&#39;Mango&#39;, &#39;fruit&#39;), &#39;my&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
  forward_static_call(&#39;fruit&#39;, &#39;my&#39;, &#39;father\&#39;s&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
 }
}
Orange::fruit(&#39;NO&#39;);
function fruit() {
 $args = func_get_args();
 echo "Apple is " . join(&#39; &#39;, $args). "\n";
}
?>
运行结果:
Orange is
Orange is my favorite fruit
Apple is my father's favorite fruit
Copier après la connexion

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
Copier après la connexion

应用

前面已经提到过了,引入后期静态绑定的目的是:用于在继承范围内引用静态调用的类。
所以, 可以用后期静态绑定的办法解决单例继承问题。

先看一下使用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) {
}
Copier après la connexion

通过上面的例子可以看到,使用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) {
}
Copier après la connexion

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

用JS检测电脑配置(附代码)

Vue.js+Flask来构建单页的App(附代码)

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal