PHP的Calling Scope
作者: Laruence( ) 本文地址: http://www.laruence.com/2012/06/14/2628.html 转载请注明出处 昨天在Yaf交流群, 大草原同学批评我变懒了, Blog很久没更新了, 今天刚好有人在Segmentfalut上问了我一个问题, ?我在微博上也做了简单的解答, 不过感觉一句话说不
- 作者: Laruence(
)
- 本文地址: http://www.laruence.com/2012/06/14/2628.html
- 转载请注明出处
昨天在Yaf交流群, 大草原同学批评我变懒了, Blog很久没更新了, 今天刚好有人在Segmentfalut上问了我一个问题, ?我在微博上也做了简单的解答, 不过感觉一句话说不清楚, 就写篇blog凑个数吧.
问题在这里, ?因为太长, 我就不copy过来了: 这是php中__call和__callStatic在被继承后会产生的bug?
这个问题乍看, 确实很容易让人迷惑, 但实际上, 造成这样的误解的根本原因在于: 在PHP中, 判断静态与否不是靠”::”(PAAMAYIM_NEKUDOTAYIM)符号, 而是靠calling scope.
那么, 什么是calling scope?
在PHP中, 调用一个方法的时候, $this指针指向的对象就是这个方法被调用时刻的calling scope. 对于下面的例子:
<?php Foo::bar(); ?>
在调用bar方法的时候, 处于一个没有calling scope域的上下文中, 所以这个是静态调用.
而对于如下的例子:
<?php class A { public function test() { Foo::bar(); } } $a = new A(); $a->test();
在调用bar方法的时候, 处于一个$a对象的上下文中, 也就是说, 此时的calling scope是$a对象, 所以这个其实不是静态调用.
为了验证这一个结论, 请看下面的一个实际例子:
<?php class Foo { public function bar() { var_dump($this); } } class A { public function test() { Foo::bar(); } } $a = new A(); $a->test(); ?>
输出什么呢?
object(A)#1 (0) { }
在调用bar的时候, 这个看似”静态”调用的调用, $this指针却是被赋值的, 指向的是$a对象, 那么这个还算静态调用么?
我举这个例子是为了说明这个问题, 但大家在实际的应用中, 大家尽量要避免使用”::”来调用一个非静态的方法, PHP也会对于这种调用给出一个Strict 警告:
Strict Standards: Non-static method Foo::bar() should not be called statically, assuming $this from incompatible context
也许有人会说这个应该算bug吧? 其实不然, 更多的应该是错误使用造成的, 因为你在一个有calling scope的上下文中采用”静态的形式”调用了一个类的非静态方法所致.
那么PHP为什么要这么设计呢? 考虑下面的例子:
<?php class A { public function __construct() { } } class B extends A { public function __construct() { parent::__construct(); } }
当我们调用父类的构造函数的时候, 我们是有意的要把当前的scope传递给父类的构造函数作为calling scope的.
现在大家对静态调用, 是不是稍微能有更进一步的理解呢? 下午公司马上就要开全体大会, 匆忙而就, 写的可能有点乱, 请大家海涵, 呵呵, thanks
Comments
- 2012/06/14, 张洋 writes: 鸟哥V5,顶了再看...... :-P
- 2012/06/14, 张洋 writes: Demon: 13:33:28 更新blog的举动让一群活不下去的人重新站起来了! ......
- 2012/06/14, ujnjing writes: 鸟哥V5~
- 2012/06/14, 陆离 writes: 今天看到鸟哥的微博也觉得挺困惑的,正在纠结呢就有了这么一篇博文。学习了。
- 2012/06/14, jarfield writes: 个人觉得最后一个parent的例子说明PHP此特性的缘由,不是很有说服力。 Java/C++中,均有“子类构造函数调用父类构造函数”的需求。Java对super 关键字做了特殊处理。PHP也完全可以对parent::做特殊处理。类似于Foo::bar的误用,可以直接报错。 这样是否更加安全一些?毕竟很多PHP程序员均有Java/C++的背景,某些概念深入人心。
- 2012/06/14, xinqiyang writes: 鸟哥的yaf群号是啥? 主要是parent::__construct(); 和普通的 class::staticfunction 记住的了。。。。。
- 2012/06/14, 子痕 writes: Yaf 群号: 5134185,多谢鸟哥授业解惑,哈哈。
- 2012/06/14, shirne writes: 似乎明白了。 呵呵
- 2012/06/15, wizardmin writes: 哈哈,之前也认为是个BUG ”::”来调用一个非静态的方法还是应该给个warning错误
- 2012/06/15, bill writes: 现丑了。 最后一个例子个人觉得不能很好的说明calling scope。 class B 的实例化对像在调用构造函数的时候,同时也会调用父类(class B)的构造函数,parent::__construct(), 这里的parent不是当前B类的实例化对像,而是Class A本身。所以这里不会是把当前的calling scope传给父类。当前的calling scope是class B的实例化对像。如果传递给父类(class A),那不就是在class A里面用class B的实例化对像(calling scope)? 对于作用域,官方文档的OOP第章好像就有例子说明。 轻拍
- 2012/06/19, 陈辉云 writes: 报不报strict,看error_reporting的设置。
- 2012/06/19, huming17 writes: test(); ?> 静态调用函数 public function bar() 定义成 public static function bar() 再静态调用,$this指针不会被赋值。
- 2012/06/20, wclssdn writes: 给力~~~ 不过. 看到那个$this竟然有值.. 还是A 我就诧异了.... 如果$this->bar2(); 那岂不是报bar2不存在A中? 看来写法的规范性是必须的啊~~ 我就一直没碰到过这问题.. 哈哈哈~~~
- 2012/06/25, PHP爱好者 writes: 表示我是个规范的写代码的人,不过看了laruence的这篇文章,还是很有收获!
- 2012/06/25, funlake writes: 给力,又学到东西了,感谢。
- 2012/07/12, eason writes: 说实话,这种作用域的东西,在任何语言里都有。 一般对javascript 运行机制,作用域,作用域链有深刻理解的人,再来看php的作用域那就更容易了。
- 2012/08/09, 奇言妙事-文学奇谈小小说阅读xlinblog.sinaapp.com » Blog Archive » PHP的Calling Scope writes: [...] 本文地址: http://www.laruence.com/2012/06/14/2628.html [...]
- 2012/08/12, PHP的Calling Scope树林/咖啡 成都专业php网站制作 | 树林/咖啡 成都专业php网站制作 writes: [...] 风雪之隅 ? PHP应用 Posted in: php / Tagged: PHP的Calling, Scope [...]
- 2012/08/30, 疯狂的火星人 writes: 再看一遍!
- 2012/09/13, PHP静态调用非静态方法 | 编程·早晨 writes: [...] 好了,对于为什么会出现这个情况的实现原因, 鸟哥的这篇文章有说明 http://www.laruence.com/2012/06/14/2628.html [...]
- 2012/09/21, x6y6 writes: 用静态方法去调用一个非静态函数,这个为什么不干脆不报错呢,因为按照其他语言,比如Java、C++是直接报错的。
- 2012/09/21, x6y6 writes: 我有点奇怪,用调用静态方法的方法去调用一个非静态方法,为什么不干脆直接报错呢,因为按照其他语言,比如Java、C++这种情况是直接报错的。
- 2012/11/19, PHP静态调用非静态方法 « 成人免费资源三级分享网站 writes: [...] 好了,对于为什么会出现这个情况的实现原因, 鸟哥的这篇文章有说明 http://www.laruence.com/2012/06/14/2628.html [...]
- 2012/11/28, Jason writes: 学习了!!!
- 2013/03/15, FxYCarl writes: 怪不得我之前在用call_user_function调用对象的方法的时候会出现没在对象上下文的提示...
- 2013/05/03, noName writes: 我觉得这是在PHP语言设计上有问题。
Related posts:
- 如何获取一个变量的名字
- Javascript作用域原理
- 深入理解PHP原理之函数(Introspecting PHP Function)
- 深入理解PHP原理之变量分离/引用(Variables Separation)
- 深入浅出PHP(Exploring PHP)
Copyright © 2010 风雪之隅 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

Visual Studio Code,也稱為 VS Code,是一個免費的原始碼編輯器 - 或整合開發環境 (IDE) - 可用於所有主要作業系統。 VS Code 擁有大量針對多種程式語言的擴展,可以輕鬆編寫

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。
