型別提示的實現

2022-03-10 15:37:17 字數 3594 閱讀 2030

php是弱型別語言,向方法傳遞引數時候也並不嚴格檢查資料型別。 不過有時需要判斷傳遞到方法中的引數,為此php中提供了一些函式,來判斷資料的型別。 比如is_numeric(),判斷是否是乙個數值或者可轉換為數值的字串,比如用於判斷物件的型別運算子:instanceof。 instanceof 用來測定乙個給定的物件是否來自指定的物件類。instanceof 運算子是 php 5 引進的。 在此之前是使用的is_a(),不過現在已經不推薦使用。

為了避免物件型別不規範引起的問題,php5中引入了型別提示這個概念。在定義方法引數時,同時定義引數的物件型別。 如果在呼叫的時候,傳入引數的型別與定義的引數型別不符,則會報錯。這樣就可以過濾物件的型別,或者說保證了資料的安全性。

php中的型別提示功能只能用於引數為物件的提示,而無法用於為整數,字串,浮點等型別提示。在php5.1之後,php支援對陣列的型別提示。

要使用型別提示,只要在方法(或函式)的物件型引數前加乙個已存在的類的名稱,當使用型別提示時, 你不僅可以指定物件型別,還可以指定抽象類和介面。

乙個陣列的型別提示示例:

function array_print(array $arr) 

array_print(1);

以上的這段**有一點問題,它觸發了我們這次所介紹的型別提示,這段**在php5.1之後的版本執行,會報錯如下:

catchable fatal error: argument 1 passed to array_print() must be an array, 

integer given, called in ...

當我們把函式引數中的整形變數變為陣列時,程式會正常執行,呼叫print_r函式輸出陣列。 那麼這個型別提示是如何實現的呢? 不管是在類中的方法,還是我們呼叫的函式,都是使用function關鍵字作為其宣告的標記, 而型別提示的實現是與函式的宣告相關的,在宣告時就已經確定了引數的型別是哪些,但是需要在呼叫時才會顯示出來。 這裡,我們從兩個方面說明型別提示的實現:

引數宣告時的型別提示

函式或方法呼叫時的型別提示

將剛才的那個例子修改一下:

function array_print(array $arr = 1) 

array_print(array(1));

這段**與前面的那個示例相比,函式的引數設定了乙個預設值,但是這個預設值是乙個整形變數, 它與引數給定的型別提示array不一樣,因此,當我們執行這段**時會很快看到程式會報錯如下:

fatal error: default value for parameters with array type hint 

can only be an array or null

為什麼為很快看到報錯呢? 因為預設值的檢測過程發生在中間**生成階段,與執行時的報錯不同,它還沒有生成中間**,也沒有執行中間**的過程。 在zend/zend_language_parser.y檔案中,我們找到函式的引數列表在編譯時都會呼叫zend_do_receive_arg函式。 而在這個函式的引數列表中,第5個引數( znode *class_type)與我們這節所要表述的型別提示密切相關。 這個引數的作用是宣告型別提示中的型別,這裡的型別有三種:

空,即沒有型別提示

類名,使用者定義或php自定義的類、介面等

陣列,編譯期間對應的token是t_array,即array字串

在zend_do_receive_arg函式中,針對class_type引數做了一系列的操作,基本上是針對上面列出的三種型別, 其中對於類名,程式並沒有判斷這個類是否存在,即使你使用了乙個不存在的類名, 程式在報錯時,顯示的也會是實參所給的物件並不是給定類的例項。

以上是宣告型別提示的過程以及在宣告過程中對引數預設值的判斷過程,下面我們看下在函式或方法呼叫時型別提示的實現。

從上面的宣告過程我們知道php在編譯型別提示的相關**時呼叫的是zend/zend_complie.c檔案中的zend_do_receive_arg函式, 在這個函式中將型別提示的判斷的opcode被賦值為zend_recv。根據opcode的對映計算規則得出其在執行時呼叫的是zend_recv_spec_handler。 其**如下:

static int zend_fastcall  zend_recv_spec_handler(zend_opcode_handler_args)

...//省略

} else

...//省略}

如上所示:在zend_recv_spec_handler中最後呼叫的是zend_verify_arg_type。其**如下:

static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type tsrmls_dc)

if (z_type_p(arg) == is_object)

} else if (z_type_p(arg) != is_null || !cur_arg_info->allow_null)

} else if (cur_arg_info->array_type_hint)

if (z_type_p(arg) != is_array && (z_type_p(arg) != is_null || !cur_arg_info->allow_null))

}return 1;}

zend_verify_arg_type的整個流程如圖3.1所示:

圖3.1 型別提示判斷流程圖

如果型別提示報錯,zend_verify_arg_type函式最後都會呼叫 zend_verify_arg_class_kind 生成報錯資訊, 並且呼叫 zend_verify_arg_error 報錯。如下所示**:

static inline char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, const char **class_name, zend_class_entry **pce tsrmls_dc) else }

static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const zend_arg_info *cur_arg_info, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind tsrmls_dc) else

if (ptr && ptr->op_array) else

return 0;}

在上面的**中,我們可以找到前面的報錯資訊中的一些關鍵字argument、 passed to、called in等。 這就是我們在呼叫函式或方法時型別提示顯示錯誤資訊的最終執行位置。

python型別提示

一 型別提示的好處 1 增強 的可讀性 2 ide中 提示 3 靜態 檢查 第三方庫 二 ide中 中提示功能 1 為引數與返回資料指定型別 def greeting name str str str 返回值也可以 return hello name.split 指定之後就可以呼叫str的方法 gr...

鏈結提示文字的實現

在web中經常碰到鏈結提示文字效果,就是當滑鼠經過url鏈結時,立刻彈出乙個提示層 div 提示鏈結內容等等相關文字.雖然知道是用隱藏div實現de.js檔案 如下 mouse on title.js var o event.srcelement mou event.x mousey event.y...

函式補充之型別提示

補充函式的知識點 型別提示 type hinting 最低 python 版本為 3.5 def register name 必須傳入名字傻叉 age 1111111,hobbbies 必須傳入愛好元組 返回的是整型 可以在函式形參的後面跟 加提示資訊 print name print age pr...