Implementation of type hints
PHP is a weakly typed language and does not strictly check the data type when passing parameters to the method. However, sometimes it is necessary to judge the arguments passed to the method, which provides some functions in PHP to determine the type of data. For example, Is_numeric (), determines whether it is a numeric value or a string that can be converted to a numeric value, such as the type operator used to determine an object: instanceof. The instanceof is used to determine whether a given object is from a specified object class. The instanceof operator was introduced in PHP 5. Prior to this is the use of is_a (), but is now deprecated. In order to avoid problems caused by non-canonical object types, the concept of type hinting was introduced in PHP5. When you define a method parameter, you define the object type of the parameter at the same time. If the type of the incoming parameter does not match the defined parameter type at the time of the call, an error is reached. This allows you to filter the type of the object, or to guarantee the security of the data. The Type hints feature in PHP can only be used for hints that are arguments to objects, not for types such as integers, strings, floating-point, and so on. After PHP5.1, PHP supports type hints for arrays. To use a type hint, you can specify not only the object type but also the abstract class and interface, as long as you add the name of an existing class to the object type parameter of the method (or function), and when you use the type hint. An example of a type hint for an array: function Array_print (array $arr) {Print_r ($arr);} Array_print (1); The above code is a bit of a problem, it triggers the type hint we introduced this time, this code in the version after PHP5.1 execution, will be error as follows: Catchable fatal Error:argument 1 passed to Array_print () must is an array, integer given, called in ... When we turn the shaping variable in the function parameter into an array, the program runs normally and calls the Print_r function output array. So how is this type of hint implemented? Regardless of the method in the class, or the function that we call, is the token that uses the Function keyword as its declaration, and the implementation of the type hint is related to the declaration of the function, which, at the time of declaration, determines the type of the parameter, but it needs to be displayed at the time of invocation. Here, we illustrate the implementation of type hints in two ways: the type hint of a parameter declaration when the type hint function or method call will change the example just now: function array_print (Array $arr = 1) {print_r ($arr);} Array_ Print(Array (1)); This code compares to the previous example, the function parameter sets a default value, but this default value is an shaping variable, it is not the same as the type hint array given by the parameter, so when we run this code we will see that the program will error as follows: Fatal Error:default value for parameters with array type hint can is only a array or null why do I see an error soon? Because the detection of the default value occurs during the intermediate code generation phase, unlike the runtime error, it has not generated intermediate code, nor has the process of executing intermediate code. In the Zend/zend_language_parser.y file, we find that the parameter list of the function calls the Zend_do_receive_arg function at compile time. In the parameter list of this function, the 5th parameter (Znode *class_type) is closely related to the type hint we want to describe in this section. The function of this parameter is to declare types in the hint type, there are three types: null, that is, there is no type hint class name, user-defined or PHP custom class, interface and other arrays, the corresponding token during compilation is T_array, that is, the array string in Zend_do_receive_ arg function, for the Class_type parameter to do a series of operations, basically for the three types listed above, where the class name, the program does not determine whether the class exists, even if you use a nonexistent class name, the program in error, The object given by the argument is not an instance of the given class. The above is the procedure for declaring type hints and the process of judging the default values of the parameters during the declaration process, and we look at the implementation of the type hint at the time of the function or method invocation. From the above declaration procedure, we know that PHP is calling the Zend_do_receive_arg function in the zend/zend_complie.c file when compiling the relevant code for the type hint, and in this function the opcode of the type hint's judgment is assigned to Zend_ RECV. According to OpCode's mapping calculation rule, it is called zend_recv_spec_handler at execution time. Its code is as follows: Static int zend_fastcall Zend_recv_spec_handler (Zend_opcode_handler_args) {...//omit if (param = = NULL) {char *space ; Char *class_name = Get_active_class_namE (&space tsrmls_cc); Zend_execute_data *ptr = EX (Prev_execute_data); if (Zend_verify_arg_type (zend_function *) EG (Active_op_array), Arg_num, NULL, Opline->extended_value TSRMLS_CC)) { ...//omit} ...//omit} else {...//omit Zend_verify_arg_type ((zend_function *) EG (Active_op_array), Arg_num, *param, Opline-> ; Extended_value tsrmls_cc); ...//omit} ...//omit} as shown above: The Last call in Zend_recv_spec_handler is Zend_verify_arg_type. Its code is as follows: static inline int Zend_verify_arg_type (zend_function *zf, Zend_uint arg_num, Zval *arg, ulong Fetch_type TSRMLS_DC) {...//omit if (cur_arg_info->class_name) {const char *class_name; if (!arg) {need_msg = Zend_verify_arg_class_kind (cur _arg_info, Fetch_type, &class_name, &ce tsrmls_cc); Return Zend_verify_arg_error (ZF, Arg_num, Cur_arg_info, need_msg, Class_name, "None", "" TSRMLS_CC);} if (z_type_p (arg) = = Is_object) {//Since it is a class object parameter, the passed parameter needs to be the object type//below to check whether this object is an instance object of the parameter hint class, here is allowed to pass the subclass instance Object need_msg = Zend_verify _arg_class_kind (Cur_arg_info, Fetch_type, &class_naMe, &ce tsrmls_cc); if (!ce | |!instanceof_function (z_objce_p (ARG), ce tsrmls_cc)) {return zend_verify_arg_error (ZF, Arg_num, Cur_arg_info, Need_msg, Class_name, "instance of", Z_objce_p (ARG)->name tsrmls_cc);}} else if (z_type_p (ARG) = Is_null | |!cur_arg_info->allow_null) {//parameter is NULL, also can be checked,//If the function defines the default value of the parameter, not passing the parameter call is also possible by Check the need_msg = Zend_verify_arg_class_kind (Cur_arg_info, Fetch_type, &class_name, &ce TSRMLS_CC); Return Zend_verify_arg_error (ZF, Arg_num, Cur_arg_info, Need_msg, Class_name, Zend_zval_type_name (ARG), "" TSRMLS_CC);} } else if (cur_arg_info->array_type_hint) {//array if (!ARG) {return zend_verify_arg_error (ZF, Arg_num, Cur_arg_info, " is an array "," "," none "," "TSRMLS_CC);} if (z_type_p (ARG) = Is_array && (z_type_p (ARG)! = Is_null | |!cur_arg_info->allow_null)) {return zend_verify_ Arg_error (ZF, Arg_num, Cur_arg_info, "is an array", "", Zend_zval_type_name (ARG), "" TSRMLS_CC);}} return 1;} The entire process of Zend_verify_arg_type is shown in 3.1: Figure 3.1 Type hints to determine the flowchart if the type prompt error, the Zend_verify_arg_type function will call Zend_verify_arg_class_kind to generate an error message, and call Zend_verify_arg_error error. Code as follows: 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) {*pce = Zend_fetch_class (Cur_arg_info->class_name, cur_arg_info-> Class_name_len, (Fetch_type | Zend_fetch_class_auto | Zend_fetch_class_no_autoload) TSRMLS_CC); *class_name = (*PCE)? (*PCE)->name:cur_arg_info->class_name;if (*pce && (*PCE)->ce_flags & Zend_acc_interface) { Return "Implement Interface";} else {return ' is an instance of ';}} static inline int zend_verify_arg_error (const zend_function *ZF, Zend_uint arg_num, const Zend_arg_info *cur_arg_info, CO NST Char *need_msg, const char *need_kind, const char *given_msg, char *given_kind tsrmls_dc) {Zend_execute_data *ptr = EG (Current_execute_data)->prev_execute_data; Char *fname = zf->common.function_name; Char *fsEp Char *fclass; if (zf->common.scope) {fsep = "::"; Fclass = Zf->common.scope->name;} else {fsep = ""; Fclass = "";} if (ptr && ptr->op_array) {zend_error (E_recoverable_error, "Argument%d passed to%s%s%s () must%s%s,%s%s giv En, called in%s on line%d and defined ", Arg_num, Fclass, Fsep, fname, Need_msg, Need_kind, Given_msg, Given_kind, PTR-&G T;op_array->filename, Ptr->opline->lineno);} else {zend_error (E_recoverable_error, "Argument%d passed to%s%s%s () must%s%s,%s%s given", Arg_num, Fclass, Fsep, Fnam E, need_msg, Need_kind, given_msg, given_kind);} return 0;} In the above code, we can find the previous error message in some of the keywords argument, passed to, called in and so on. This is where the type hint displays the final execution location of the error message when the function or method is called.
http://www.bkjia.com/PHPjc/963684.html www.bkjia.com true http://www.bkjia.com/PHPjc/963684.html techarticle implementation of type hints PHP is a weakly typed language and does not strictly check the data type when passing parameters to the method. However, sometimes it is necessary to determine the parameters passed to the method, which is provided in PHP ...