摘要:保持目前的情況,除動(dòng)態(tài)生成實(shí)例時(shí)需要完全限定類名,并無(wú)其他槽點(diǎn)。本文所討論的根據(jù)類名動(dòng)態(tài)生成對(duì)象,就要無(wú)視當(dāng)前所在或引入的名字空間,必須使用完全限定類名形式。作為對(duì)比,不能動(dòng)態(tài)生成對(duì)象。
轉(zhuǎn)載請(qǐng)注明文章出處:https://tlanyan.me/dynamic-ne...問(wèn)題
前幾天有人在PHP的QQ群里問(wèn)生成對(duì)象的問(wèn)題:
use AB; $b = new B(); // 正確 $str = "B"; $b = new $str(); // 錯(cuò)誤,提示:類"B"未找到
類似問(wèn)題五六年前碰到過(guò),因此印象深刻。熱心提示要用 "完全限定類名" 形式,可惜連說(shuō)兩遍,提問(wèn)題的人都沒(méi)理解我說(shuō)的(或者認(rèn)為我的回復(fù)與其問(wèn)題無(wú)關(guān)):
不得已下,寫下示范代碼并 @ 提問(wèn)題的人,終于讓其明白:
原理問(wèn)題解決了,背后的原理是什么?
從人的角度看,代碼意圖非常明顯:動(dòng)態(tài)生成類B的實(shí)例。但從執(zhí)行引擎的角度,完全是另外一回事。其實(shí)new $classname()背后的運(yùn)作行為類似于:
// 偽代碼 if (class_exists($str)) { $b = new $str(); return $b; } throw ClassNotFoundException; // 或者用反射 try { $reflectionClass = new ReflectionClass($str); $b = $reflectionClass.newInstance(); return $b; } throw ClassNotFoundException;
要根據(jù)類名動(dòng)態(tài)生成示例,首先要判斷類是否存在吧?PHP中與之相關(guān)的是class_exists函數(shù)和ReflectionClass類。在上面的例子中,只傳入字符串 "B",class_exists回返回true嗎?
答案是否定的。class_exists和ReflectionClass只會(huì)在全局類列表中根據(jù)名字查找,不會(huì)理會(huì)調(diào)用函數(shù)所在(或引入)的名字空間。同理,如果使用use引入類名并做別名(as),別名類在class_exists中也會(huì)返回false。
那么PHP能否改進(jìn)一下class_exists和ReflectionClass的行為,讓其根據(jù)當(dāng)前上下文判斷?
可以這么做,但是代價(jià)很大,原因包括:
class_exists和ReflectionClass都沒(méi)有指示程序上下文Context的參數(shù);
PHP比較坑的一點(diǎn):類名不會(huì)像函數(shù)、常量一樣往上逐級(jí)查找;
如果存在多個(gè)同名的類,加載哪個(gè)?如以下代碼所示:
不管采取哪種行為,都會(huì)招致吐槽。
保持目前的情況,除動(dòng)態(tài)生成實(shí)例時(shí)需要完全限定類名,并無(wú)其他槽點(diǎn)。并且實(shí)現(xiàn)上簡(jiǎn)單,行為明確且一致。
總結(jié)作為一門腳本語(yǔ)言,PHP非常的靈活,但也會(huì)帶來(lái)一些使用上的困惑。本文所討論的根據(jù)類名動(dòng)態(tài)生成對(duì)象,就要無(wú)視當(dāng)前所在或引入的名字空間,必須使用完全限定類名形式。
作為對(duì)比,C++不能動(dòng)態(tài)生成對(duì)象。Java要用Class.forName的方式獲取class對(duì)象,然后再調(diào)用構(gòu)造函數(shù)生成。Java不能直接new類名,避免了PHP中的坑,但Class.forName同樣需要完全限定類名,避免不明確行為。
參考PHP回顧之反射
PHP中的重載
Using namespaces: fallback to global function/constant
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/30910.html
摘要:代理模式從類型上來(lái)說(shuō),可以分為靜態(tài)代理和動(dòng)態(tài)代理兩種類型。然而今天的重點(diǎn)是我們都知道牛逼轟轟的的實(shí)現(xiàn)的一種方式是使用的動(dòng)態(tài)代理另一種是,大部分人也會(huì)用的動(dòng)態(tài)代理,不過(guò)沒(méi)有研究過(guò)的動(dòng)態(tài)代理到底是怎么實(shí)現(xiàn)的。 動(dòng)態(tài)代理 代理模式是設(shè)計(jì)模式中非常重要的一種類型,而設(shè)計(jì)模式又是編程中非常重要的知識(shí)點(diǎn),特別是在業(yè)務(wù)系統(tǒng)的重構(gòu)中,更是有舉足輕重的地位。代理模式從類型上來(lái)說(shuō),可以分為靜態(tài)代理和動(dòng)態(tài)代...
摘要:動(dòng)態(tài)代理深度解析引言說(shuō)起動(dòng)態(tài)代理,很多人可能都沒(méi)有直接去使用過(guò)。因?yàn)榈膭?dòng)態(tài)代理只能代理接口,而不能代理原始的類。接下來(lái)是真正壓軸的環(huán)節(jié),實(shí)現(xiàn)自己的動(dòng)態(tài)代理類。 Java動(dòng)態(tài)代理深度解析 引言 說(shuō)起動(dòng)態(tài)代理,很多人可能都沒(méi)有直接去使用過(guò)。但是只要用過(guò)Spring,那動(dòng)態(tài)代理就是一個(gè)是個(gè)繞不過(guò)的坎,因?yàn)镾pring的核心特性之一AOP就是基于動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)的,那么什么情況下需要用到動(dòng)態(tài)代理...
摘要:如何修改代碼為了盡量減少程序員的工作,我們的代碼生成器在生成完后,還需要將方法的返回值自動(dòng)修改成這個(gè)類。具體的實(shí)現(xiàn)到此為止,基本上代碼生成器的主要障礙都有了相應(yīng)的處理辦法。 當(dāng)前的狀況 一般做數(shù)據(jù)庫(kù)相關(guān)開(kāi)發(fā), 除非學(xué)習(xí), 否則很少有人愿意直接使用JDBC。本來(lái)Java代碼就比較啰嗦了,而直接用JDBC寫代碼之啰嗦簡(jiǎn)直有些令人發(fā)狂!所以在實(shí)際開(kāi)發(fā)過(guò)程中,我們通常都會(huì)使用一些框架/庫(kù)來(lái)幫助...
閱讀 774·2019-08-29 12:49
閱讀 3562·2019-08-29 11:32
閱讀 3457·2019-08-26 10:43
閱讀 2412·2019-08-23 16:53
閱讀 2061·2019-08-23 15:56
閱讀 1709·2019-08-23 12:03
閱讀 2780·2019-08-23 11:25
閱讀 2094·2019-08-22 15:11