static int ZEND_FASTCALL  ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{...//省略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)) {...//省略}...//省略} else {...//省略zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);...//省略}...//省略
}

如上所示:在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 (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) { // 既然是类对象参数, 传递的参数需要是对象类型// 下面检查这个对象是否是参数提示类的实例对象, 这里是允许传递子类实例对象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) { // 参数为NULL, 也是可以通过检查的,// 如果函数定义了参数默认值, 不传递参数调用也是可以通过检查的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) { //  数组if (!arg) {return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be 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, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC);}}return 1;
}

zend_verify_arg_type的整个流程如图3.1所示:


如果类型提示报错,zend_verify_arg_type函数最后都会调用 zend_verify_arg_class_kind 生成报错信息, 并且调用 zend_verify_arg_error 报错。如下所示代码:

tatic 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 "be 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_msg, 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, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);}return 0;
}
在上面的代码中,我们可以找到前面的报错信息中的一些关键字Argument、 passed to、called in等。
这就是我们在调用函数或方法时类型提示显示错误信息的最终执行位置。

http://www.php-internals.com/book/?p=chapt03/03-05-impl-of-type-hint

28.类型提示的实现相关推荐

  1. 第八章 函数中的类型提示

    应该强调的是,Python 仍将是一种动态类型的语言,即使按照惯例,作者也不希望强制类型提示 --Guido van Rossum, Jukka Lehtosalo, and Łukasz Langa ...

  2. 全面理解Python中的类型提示(Type Hints)

    众所周知,Python 是动态类型语言,运行时不需要指定变量类型.这一点是不会改变的,但是2015年9月创始人 Guido van Rossum 在 Python 3.5 引入了一个类型系统,允许开发 ...

  3. python 功能 代码_让你的Python代码实现类型提示功能

    Python是一种动态类型语言,这意味着我们在编写代码的时候更为自由,但是与此同时IDE无法向静态类型语言那样分析代码,及时给我们相应的提示.为了解决这个问题,Python 3.6 新增了几个特性PE ...

  4. php 类示例,PHP类实例教程(二十二):类型提示

    PHP是弱类型语言,向方法传递参数时候也不太区分类型.这样的使用会引起很多的问题,PHP开发者认为,这些问题应该是由代码书写者在书写代码时进行检验以避免.没有类型提示很危险. class Normal ...

  5. python语言必背代码-让你的Python代码实现类型提示功能

    Python是一种动态类型语言,这意味着我们在编写代码的时候更为自由,但是与此同时IDE无法向静态类型语言那样分析代码,及时给我们相应的提示.为了解决这个问题,Python 3.6 新增了几个特性PE ...

  6. php 单元测试 静态类,可选的PHP类型提示/检查单元测试或静态分析?

    PHP类型提示不支持标量变量[1],如int或string 但是,我们发现在连续集成期间注释函数中的类型(int或string)以发现错误仍然非常有用,例如: 目前我用的方法就像 function f ...

  7. python应用程序类型_python – 类型提示条件可变参数应用程序

    我试图键入提示构造函数的部分应用程序,一旦提供"tag"实例,它就会被完全应用.这是通过包装类实现的,包装类存储构造函数和任何部分应用的参数.由于包装器适用于多种类型,因此必须采用 ...

  8. php 显示对像编码,PHP面向对象之旅:类型提示

    PHP是弱类型语言,向方法传递参数时候也不太区分类型.这样的使用会引起很多的问题,PHP开发者认为,这些问题应该是由代码书写者在书写代码时进行检验以避免. 没有类型提示很危险 下面的代码可能会出现问题 ...

  9. python类型提示模块包_Python checktypes包_程序模块 - PyPI - Python中文网

    checktypes软件包 用于创建实用程序类的库,为类型提供了良好的抽象 检查和数据验证. 基本示例 创建 面向对象的api 在要继承的CheckType旁边选择一个基类并定义一个predicate ...

  10. clion中自定义消息msg消息时定义的msg文件有类型提示

    clion中自定义消息msg消息时定义的msg文件有类型提示 Ros Support 插件安装

最新文章

  1. 计算机设备布局图,针对不同设备类型创建仪表板布局
  2. Android 实现Activity后台运行
  3. re正则表达式公式讲解5
  4. ZZULIOJ 1111: 多个整数的逆序输出(函数专题)
  5. 又一次摔MFC坑里了
  6. Linux系列-Red Hat5平台下的DHCP服务搭建
  7. Linux段错误-转
  8. Win10设置mac
  9. [Matlab]切比雪夫Ⅱ型滤波器设计:低通、高通、带通和带阻
  10. python批量获取百度贴吧_python网络爬虫案例:批量爬取百度贴吧页面数据
  11. Python —— 修改桌面壁纸
  12. 下载kaggle数据集
  13. 二元函数连续性、可导性及极限
  14. ImageJ Merge荧光图片
  15. 黑鲨装机大师一键重装系统图文
  16. 从开题报告到毕业论文|软件工具大公开
  17. ElasticSearch(ik分词器)+SpringBoot站内全文搜索解决方案
  18. 最佳37个获取LOGO设计灵感的网站推荐
  19. linux下部署项目,下载文件时,中文文件名乱码问题
  20. 程序设计入门-java

热门文章

  1. javaWEB总结(29):理解多个Filter代码的执行顺序
  2. 使用notebook 笔记(1)
  3. 升级设置win2008r2开发环境,遇到问题小结
  4. SQLServer表字段默认值相关信息的获取方法
  5. Kernel: Do NOT use global variable as possible as you can 尽量不使用全局变量
  6. 在asp.net中怎样将输入的中文符号转换成英文符号
  7. 使用ggplot2绘制心形
  8. 两年前端历程回顾的思考与总结
  9. SVN commit failed: 'xxx' is not under version control
  10. CentOS7.6上搭建阿里云OSS的C SDK