搜尋
首頁web前端js教程PHP靜態綁定使用詳解
PHP靜態綁定使用詳解May 09, 2018 am 11:24 AM
php使用詳解

這次帶給大家PHP靜態綁定使用詳解,PHP靜態綁定使用的注意事項有哪些,以下就是實戰案例,一起來看一下。

基礎

#1.範圍解析運算子(::)

  • 可以用於存取靜態成員,類別常數,也可以用來覆寫類別中的屬性和方法

  • self,parent 和 static 這三個特殊的關鍵字是用於在類別定義的內部對其屬性或方法進行存取的。

  • parent用於呼叫父類別中被覆寫的屬性或方法(出現在哪裡,就將解析為對應類別的父類別)。

  • self用於呼叫本類別中的方法或屬性(出現在哪裡,就將解析為對應的類別;注意與$this區別,$this指向當前實例化的對象)。

  • 當子類別覆寫其父類別中的方法時,PHP 不會呼叫父類別中已被覆寫的方法。是否呼叫父類別的方法取決於子類別。

2. PHP核心將類別的繼承實作放在了"編譯階段"

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

運行結果:

AA
AA

結論:

self::和parent::出現在某個類別X的定義中,則會被解析為對應的類X,除非在子類別中覆寫父類別的方法。

3.Static(靜態)關鍵字

作用:

- 在函數體內的修飾變數的static關鍵字用於定義靜態局部變數。
- 用於修飾類別成員函數和成員變數時用於宣告靜態成員。
- (PHP5.3之後)在作用域解析符(::)前又表示靜態延遲綁定的特殊類別。

範例:

定義靜態局部變數(出現位置:局部函數中)

特徵:靜態變數只在局部函數域中存在,但當程序執行離開此作用域時,其值並不遺失。

<?php function test()
{
 static $count = 0;
 $count++;
 echo $count;
 if ($count < 10) {
  test();
 }
 $count--;
}

定義靜態方法,靜態屬性

a)宣告類別屬性或方法為靜態,就可以不實例化類別而直接存取。

b)靜態屬性不能透過一個類別已實例化的物件來存取(但靜態方法可以)

c)如果沒有指定存取控制,屬性和方法預設為公有。

d)由於靜態方法不需要透過物件即可調用,所以偽變數 $this 在靜態方法中不可用。

e)靜態屬性不可以由物件透過 -> 操作符來存取。

f)用靜態方式呼叫非靜態方法會導致一個 E_STRICT 等級的錯誤。

g)就像其它所有的 PHP 靜態變數一樣,靜態屬性只能被初始化為文字或常數,不能使用表達式。所以可以把靜態屬性初始化為整數或數組,但不能初始化為另一個變數或函數回傳值,也不能指向一個物件。

a.靜態方法範例(出現位置: 類別的方法定義)

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

b.靜態屬性範例(出現位置:類別的屬性定義)

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

c.用於後期靜態綁定(出現位置: 類別的方法中,用於修飾變數或方法)

下面詳細分析

後期靜態綁定(late static binding)

自PHP 5.3.0 起,PHP 增加了一個稱為後期靜態綁定的功能,用於在繼承範圍內引用靜態呼叫的類別。

1.轉送呼叫與非轉送呼叫

轉送呼叫:

指的是透過以下幾種方式進行的靜態呼叫:self: :,parent::,static:: 以及forward_static_call()。

非轉送呼叫:

明確指定類別名稱的靜態呼叫(例如Foo::foo())

非靜態呼叫(例如$foo->foo( ))

2.後期靜態綁定工作原理

原理:存储了在上一个“非转发调用”(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 = &#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

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中文网其它相关文章!

推荐阅读:

Vue如何使用动态刷新Echarts组件

vuex使用步骤详解

Vue.js里computed使用案例详解

以上是PHP靜態綁定使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace("&nbsp;","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么读取字符串后几个字符php怎么读取字符串后几个字符Apr 22, 2022 pm 08:31 PM

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
1 個月前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)