PHP中的過載

2021-09-11 09:43:52 字數 2988 閱讀 6462

先區分一下過載(overload)和重寫(override):過載指多個名字相同,但引數不同的函式在同一作用域並存的現象;重寫出現在繼承中,指子類重定義父類功能的現象,也被稱為覆蓋。過載中說的引數不同有三種情況:引數個數不同,引數型別不同,引數順序不同。重寫一般指函式的覆蓋,即相同簽名的成員函式在子類中重新定義(實現抽象函式或介面不是重寫),是實現多型(polymorphism)的一種關鍵技術。成員變數也可以過載/覆蓋,但一般不會這麼做。

用簡單的c**來說明過載:

int add(int a, int b) 

double add(double a, double b)

double add(int a, int b, double c)

double add(double a, int b, int c)

複製**

第乙個函式為參考基準,其他三個對應過載的三種情形。函式過載多見於強型別語言,編譯後函式在函式符號表的名稱一般是函式名加引數型別。上面的四個函式,g++編譯後,nm命令檢視符號表中的名字,輸出如下:

[tlanyan@server ~]# nm test | grep add

0000000000400730 t _global__sub_i__z3addii

0000000000400851 t _z3adddd

00000000004008b1 t _z3adddii

000000000040083d t _z3addii

000000000040087d t _z3addiid

複製**

最後四行的第三列對應編譯後四個函式的符號資訊,_z3為字首,add是函式名,剩下的字母d代表double,i代表int,與生命一一對應。

再回到php的過載。php的函式宣告中引數無需宣告型別,直接排除引數型別不同、引數順序不同兩種過載,只剩下引數個數不同一條路可走。定義乙個引數個數不同名字相同的函式,這麼乙個小小的過載要求,在php中也是不合法的!原因是php中不允許同名函式存在,想定義重名函式,死心吧!雖然大多數情況下以預設引數方式實現過載基本上夠用,但不時還會覺得憋屈,忍不住想問一句:php為什麼不允許(同名函式)過載啊?!

php不支援同名函式的過載是有原因的。上面已經提到,php函式宣告時不需要指定引數型別,過載中的三種情況立馬廢掉兩種。倖存的引數個數不同這一條路也走不通,為什麼呢?因為php中呼叫函式時,少傳引數,不行;多傳引數,沒問題!來個簡單的例子:

function foo($arg1, $arg2) 

// 函式呼叫

//php warning: missing argument 2 for foo()

// php notice: undefined variable: arg2 in php shell code on line 2

foo("tlanyan");

// 引數個數正好,執行正常

foo("hello", "tlanyan");

// 多傳引數,執行正常

foo("hello", "tlanyan", "nice day");

// 傳更多引數,也一切正常

foo("hello", "tlanyan", "morning", "noon", "afternoon", "evening", "night");

複製**

只要個數不小於宣告的,傳多少引數php不管。所以引數個數不同,在php中不足以區分函式。

個人認為另乙個不允許名函式存在的重要原因是function_existsmethod_existsis_callable這些api的存在。作為簡單易用的語言,php為開發人員提供了查詢函式名是否存在/可用的便利api,這在程式語言中很少見(尤其是get_defined_functions這類api)。可以看到,這些api都不需要引數資訊。如果能定義引數不同的過載函式,這些api都要跟著改,勢必引入額外的複雜性。正所謂魚與熊掌不可兼得,方便你用時沒想到引數不同,不方便你定義就抱怨,好像不好吧?

php5引入了反射api,這是非常強大的型別資訊查詢工具。就函式宣告而言,reflectionmethod/reflectionfunction類的getparameters/getnumberofparameters/getnumberofrequiredparameters等api,功能上甩function_exists等好幾條街。有了反射機制,按理說function_exists這些api可以安心的退休。雖然反射這一套東西功能強大,但遠沒有舊式api簡單好用。再加上看看市面上的**,有多少類庫和框架依賴舊式api。從相容性和實用性考慮,個人認為短時間內能以同名函式方式過載的概率非常小。

只看完上面的內容就說php不支援過載,我想隨便乙個資深的php開發都會不由自主的取下拖鞋,然後教你什麼是php中的過載,並保證至少有好幾種實現方法;官方人員對這種認知估計也無力吐槽:能不能好好看官方文件?!官網中可是有一節專門講過載!

因為種種原因,php不支援傳統的過載,也就是同名函式的過載,但php是支援過載的,而且姿勢還不少。簡單來說,php中主要有以下幾種過載方式:

預設引數,定義乙個全面的函式版本,不是必須的值在宣告時賦予預設值;

定義乙個不宣告引數的入口函式,函式內使用func_num_args/func_get_args獲取引數個數/陣列,然後根據引數個數**到具體實現的函式;

自php5.6起,可以用變長引數實現過載,func_get_args的另一種形式;

對於類中的成員函式,可以通過__call__callstatic實現過載。

php的特性決定了其不支援同名函式方式的過載,但並不意味著php不支援過載。實際上php可以多種方式實現過載,並保持其一貫的簡單易用性。

感謝閱讀!

php.net/manual/it/l…

php中的過載

php中的 過載 與其它絕大多數物件導向語言不同。傳統的 過載 是用於提供多個同名的類方法,但各方法的引數型別和個數不同。php所提供的 過載 overloading 是指動態地 建立 類屬性和方法,是通過魔術方法 magic methods 來實現的。具體來說分為兩類 1.屬性過載 public ...

PHP中的過載

先區分一下過載 overload 和重寫 override 過載指多個名字相同,但引數不同的函式在同一作用域並存的現象 重寫出現在繼承中,指子類重定義父類功能的現象,也被稱為覆蓋。過載中說的引數不同有三種情況 引數個數不同,引數型別不同,引數順序不同。重寫一般指函式的覆蓋,即相同簽名的成員函式在子類...

php中過載的概念

class stu stu1 new stu stu1 name xiaoming 屬性不存在 為物件自動新增 stu1 getname 不存在 報錯 上例中 定義了乙個stu類,類內只有 age屬性,當將其實例化後,由於類內未定義name屬性,stu1物件新增了該屬性,並對該屬性賦值。所以相當於該...