欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解PHP后期靜態(tài)綁定分析與應(yīng)用

 更新時(shí)間:2018年03月21日 08:49:19   投稿:laozhang  
這篇文章給大家總結(jié)了PHP后期靜態(tài)綁定分析與應(yīng)用的相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友可以學(xué)習(xí)下。

基礎(chǔ)知識(shí)

1. 范圍解析操作符 (::)

  • 可以用于訪問(wèn)靜態(tài)成員,類常量,還可以用于覆蓋類中的屬性和方法。
  • self,parent 和 static 這三個(gè)特殊的關(guān)鍵字是用于在類定義的內(nèi)部對(duì)其屬性或方法進(jìn)行訪問(wèn)的。
  • parent用于調(diào)用父類中被覆蓋的屬性或方法(出現(xiàn)在哪里,就將解析為相應(yīng)類的父類)。
  • self用于調(diào)用本類中的方法或?qū)傩裕ǔ霈F(xiàn)在哪里,就將解析為相應(yīng)的類;注意與$this區(qū)別,$this指向當(dāng)前實(shí)例化的對(duì)象)。
  • 當(dāng)一個(gè)子類覆蓋其父類中的方法時(shí),PHP 不會(huì)調(diào)用父類中已被覆蓋的方法。是否調(diào)用父類的方法取決于子類。

2. PHP內(nèi)核將類的繼承實(shí)現(xiàn)放在了"編譯階段"

<?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();

運(yùn)行結(jié)果:

AA
AA

結(jié)論:

self::和parent::出現(xiàn)在某個(gè)類X的定義中,則將被解析為相應(yīng)的類X,除非在子類中覆蓋父類的方法。

3.Static(靜態(tài))關(guān)鍵字

作用:

- 在函數(shù)體內(nèi)的修飾變量的static關(guān)鍵字用于定義靜態(tài)局部變量。
- 用于修飾類成員函數(shù)和成員變量時(shí)用于聲明靜態(tài)成員。
- (PHP5.3之后)在作用域解析符(::)前又表示靜態(tài)延遲綁定的特殊類。

例子:

定義靜態(tài)局部變量(出現(xiàn)位置:局部函數(shù)中)

特征:靜態(tài)變量?jī)H在局部函數(shù)域中存在,但當(dāng)程序執(zhí)行離開(kāi)此作用域時(shí),其值并不丟失。

<?php
function test()
{
 static $count = 0;

 $count++;
 echo $count;
 if ($count < 10) {
  test();
 }
 $count--;
}

定義靜態(tài)方法,靜態(tài)屬性

a)聲明類屬性或方法為靜態(tài),就可以不實(shí)例化類而直接訪問(wèn)。

b)靜態(tài)屬性不能通過(guò)一個(gè)類已實(shí)例化的對(duì)象來(lái)訪問(wèn)(但靜態(tài)方法可以)

c)如果沒(méi)有指定訪問(wèn)控制,屬性和方法默認(rèn)為公有。

d)由于靜態(tài)方法不需要通過(guò)對(duì)象即可調(diào)用,所以偽變量 $this 在靜態(tài)方法中不可用。

e)靜態(tài)屬性不可以由對(duì)象通過(guò) -> 操作符來(lái)訪問(wèn)。

f)用靜態(tài)方式調(diào)用一個(gè)非靜態(tài)方法會(huì)導(dǎo)致一個(gè) E_STRICT 級(jí)別的錯(cuò)誤。

g)就像其它所有的 PHP 靜態(tài)變量一樣,靜態(tài)屬性只能被初始化為文字或常量,不能使用表達(dá)式。所以可以把靜態(tài)屬性初始化為整數(shù)或數(shù)組,但不能初始化為另一個(gè)變量或函數(shù)返回值,也不能指向一個(gè)對(duì)象。

a.靜態(tài)方法例子(出現(xiàn)位置: 類的方法定義)

<?php
class Foo {
 public static function aStaticMethod() {
  // ...
 }
}

Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod(); // 自PHP 5.3.0后,可以通過(guò)變量引用類
?> 

b.靜態(tài)屬性例子(出現(xiàn)位置:類的屬性定義)

<?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.用于后期靜態(tài)綁定(出現(xiàn)位置: 類的方法中,用于修飾變量或方法)

下面詳細(xì)分析

后期靜態(tài)綁定(late static binding)

自 PHP 5.3.0 起,PHP 增加了一個(gè)叫做后期靜態(tài)綁定的功能,用于在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。

1.轉(zhuǎn)發(fā)調(diào)用與非轉(zhuǎn)發(fā)調(diào)用

轉(zhuǎn)發(fā)調(diào)用 :

指的是通過(guò)以下幾種方式進(jìn)行的靜態(tài)調(diào)用:self::,parent::,static:: 以及 forward_static_call()。

非轉(zhuǎn)發(fā)調(diào)用 :

明確指定類名的靜態(tài)調(diào)用(例如Foo::foo())

非靜態(tài)調(diào)用(例如$foo->foo())

2.后期靜態(tài)綁定工作原理

原理:存儲(chǔ)了在上一個(gè)“非轉(zhuǎn)發(fā)調(diào)用”(non-forwarding call)中的類名。意思是當(dāng)我們調(diào)用一個(gè)轉(zhuǎn)發(fā)調(diào)用的靜態(tài)調(diào)用時(shí),實(shí)際調(diào)用的類是上一個(gè)非轉(zhuǎn)發(fā)調(diào)用的類。

例子分析:

<?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(); //非轉(zhuǎn)發(fā)調(diào)用 ,進(jìn)入test()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C
 *
 * //當(dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C
 * public static function test() {
 *  A::foo(); //非轉(zhuǎn)發(fā)調(diào)用, 進(jìn)入foo()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為A,然后實(shí)際執(zhí)行代碼A::foo(), 轉(zhuǎn) 0-0
 *  parent::foo(); //轉(zhuǎn)發(fā)調(diào)用, 進(jìn)入foo()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C, 此處的parent解析為A ,轉(zhuǎn)1-0
 *  self::foo(); //轉(zhuǎn)發(fā)調(diào)用, 進(jìn)入foo()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C, 此處self解析為B, 轉(zhuǎn)2-0
 * }
 *
 *
 * 0-0
 * //當(dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為A
 * public static function foo() {
 *  static::who(); //轉(zhuǎn)發(fā)調(diào)用, 因?yàn)楫?dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為A, 故實(shí)際執(zhí)行代碼A::who(),即static代表A,進(jìn)入who()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名依然為A,因此打印 “A”
 * }
 *
 * 1-0
 * //當(dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C
 * public static function foo() {
 *  static::who(); //轉(zhuǎn)發(fā)調(diào)用, 因?yàn)楫?dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C, 故實(shí)際執(zhí)行代碼C::who(),即static代表C,進(jìn)入who()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名依然為C,因此打印 “C”

 * }
 *
 * 2-0
 * //當(dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C
 * public static function foo() {
 *  static::who(); //轉(zhuǎn)發(fā)調(diào)用, 因?yàn)楫?dāng)前的“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名為C, 故實(shí)際執(zhí)行代碼C::who(),即static代表C,進(jìn)入who()調(diào)用后,“上一次非轉(zhuǎn)發(fā)調(diào)用”存儲(chǔ)的類名依然為C,因此打印 “C”
 * }
 */


故最終結(jié)果為:
A::foo()
A
A
parent::foo()
A
C
self::foo()
A
C

3.更多靜態(tài)后期靜態(tài)綁定的例子

a)Self, Parent 和 Static的對(duì)比

<?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();

?>

運(yùn)行結(jié)果:
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";
}

?>


運(yùn)行結(jié)果:
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();

?>



運(yùn)行結(jié)果:
Mango
Orange

應(yīng)用

前面已經(jīng)提到過(guò)了,引入后期靜態(tài)綁定的目的是:用于在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。
所以, 可以用后期靜態(tài)綁定的辦法解決單例繼承問(wèn)題。

先看一下使用self是一個(gè)什么樣的情況:

<?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);




運(yùn)行結(jié)果:
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) {
}

通過(guò)上面的例子可以看到,使用self,實(shí)例化得到的都是類A的同一個(gè)對(duì)象

再來(lái)看看使用static會(huì)得到什么樣的結(jié)果

<?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);




運(yùn)行結(jié)果:
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) {
}

可以看到,使用static可以解決self時(shí)出現(xiàn)的單例繼承問(wèn)題。

相關(guān)文章

最新評(píng)論