PHP is a weakly typed language, and the data type is not strictly checked when passing parameters to a method. However, sometimes it is necessary to judge the parameters passed to the method, and this PHP provides a number of functions to determine the type of data. such as Is_numeric (), determine whether 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. Instanceof is used to determine whether a given object is from a specified object class. The instanceof operator is introduced in PHP 5. This is the is_a () used before, but it is now deprecated. In order to avoid the problem caused by nonstandard object type, the concept of type hint is introduced in PHP5. When you define a method parameter, you define the object type of the parameter as well. If the type of the incoming parameter does not match the defined parameter type at the time of the call, an error will be invoked. This allows you to filter the type of objects, or to ensure the security of the data. Type hints in PHP can only be used for hints that are arguments to objects, but not for integers, strings, floating-point types, 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 when you use a type hint, as long as you add the name of an existing class to the object type parameter of the method (or function). Example of an array type hint: function array_print (array $arr) {Print_r ($arr);} array_print (1); The above code has a bit of a problem, it triggers the type hint we introduced this time, the code after the PHP5.1 version executes, will be the following error: catchable fatal error:argument 1 passed to Array_print ( ) must be a array, integer given, called in When we change the shape variable in the function argument to an array, the program runs normally, calling the Print_r function output array. So how is this type hint implemented? Whether it's a method in a class, or the function we call is the token of its declaration using a function keyword, and the implementation of the type hint is related to the declaration of the function, and the type of the parameter is determined when it is declared, but it needs to be displayed when the call is made. Here, we explain the implementation of the type hint from two aspects: the type hint function when parameter declaration or the type hint of the method call to modify the example just now: FUnction array_print (Array $arr = 1) { print_r ($arr);} Array_print (Array (1)); This code has a default value compared to the previous example, but the default value is a shape variable that is not the same as the type hint array given by the argument, so when we run this code, we quickly see that the program complains as follows: Fatal error: The Default value for parameters with array type hint can is an array or NULL why did you see the error quickly? Because the default value detection process occurs in the intermediate code generation phase, unlike the run-time error, it does not generate intermediate code, nor does it perform the process of intermediate code execution. In the Zend/zend_language_parser.y file, we find the parameter list of the function and call the Zend_do_receive_arg function at compile time. In the argument list of this function, the 5th argument (Znode *class_type) is closely related to the type hint we are going to express in this section. The function of this parameter is to declare the type in the type hint, there are three kinds of types: NULL, that is, there is no type hint class name, user-defined or PHP custom class, interface, etc. array, 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, which for the class name, the program does not determine whether the class exists, even if you use a Non-existent class name, the program in the error, It also shows that the object given by the argument is not an instance of the given class. This is the process of declaring a type hint and the process of determining the default value of the parameter during the declaration process, and let's look at the implementation of the type hint at the time of the function or method invocation. From the above declaration process we know that PHP calls the Zend_do_receive_arg function in the zend/zend_complie.c file when compiling the relevant code for the type hint, in which the opcode of the judgment of the type hint is assigned to Zend_ RECV. According to OpCode's mapping calculation rules, 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 & nbsp if (param = NULL) { Char *space &NBS P 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) { ...//province Slightly ...//Skip } else { .../skip , Zend_verify_arg_type (zend_function *) EG (Active_op_array), Arg_num, *param, Opline->extended_value tsrmls_cc); ...//omit } ...//omit} as shown above: in Zend_recv_spe The last call in the C_handler is Zend_verify_arg_type. The 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) { ...//ellipsis if (cur_arg_info->class_name) { Const CH AR *class_name; (!arg) { need_msg = Zend_verify_arg_class_kind (Cur_arg_info, Fetch_typ E, &class_name, &ce tsrmls_cc); return Zend_verify_arg_error (ZF, Arg_num, Cur_arg_info, need_msg, Class_name, "None", "" Tsrml S_CC); } if (z_type_p (arg) = = Is_object) {//Since it is a class object parameter, the passed parameter needs to be the object type //Down Face to check whether this object is an instance object of the parameter hint class, here is the Allow Pass 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)) { &NBS P 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 , can also be checked by the &NBS P &NB Sp //If the function defines a parameter default value, no parameter calls can be passed through the check 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, "being an array", "" , "None", "" tsrmls_cc); } if (z_type_p (ARG)!= Is_array && (z_type_p (ARG)!= Is_nu LL!cur_arg_info->allow_null) { return Zend_verify_arg_error (ZF, Arg_num, CU R_arg_info, "Being an array", "", Zend_zval_type_name (ARG), "" tsrmls_cc); } { return 1;} The entire process of zend_verify_arg_type is shown in Figure 3.1: Figure 3.1 Type hint judgment flowchart If the type prompts an error, the Zend_verify_arg_type function will eventually call Zend_ Verify_arg_class_kind generates an error message and invokes a zend_verify_arg_error error. Code shown below: 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, const 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 given, called in%s on line%d and defined, Arg_num, Fclass, Fsep, fname, Need_msg, Need_kind, Given_ms G, Given_kind, Ptr->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, FC Lass, Fsep, fname, Need_msg, Need_kind, given_msg, Given_kind); return 0;} In the code above, we can find some of the key words in the previous error message argument, passed to, called in, and so on. This is the final execution location where the type hint displays the error message when we call a function or method.
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.