is_array 函数源码分析

本文首发于 https://github.com/suhanyujie/learn-computer/blob/master/src/function/array/is_array.md

基于PHP 7.3.3

php 中的 is_array

  • php 中的 is_array,它的签名是 is_array ( mixed $var ) : bool

实现的源码

  • \ext\standard\type.c 中可以找到 PHP_FUNCTION(is_array) 所处的位置,大概位于 273 行。
  • 在 PHP 中,这个系列的函数,是由很多个,除了它本身之外,还有 is_bool 、 is_countable 、 is_callback 、 is_int 、 is_object 、 is_string 等等
  • 在它们之中,大部分的源代码也都是和 is_array 的类似:
PHP_FUNCTION(is_array)
{php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_ARRAY);
}
  • 它的定义很简洁,直接调用了 php_is_type ,宏 INTERNAL_FUNCTION_PARAM_PASSTHRU 的作用是,将调用 is_array 时的参数,原样传递给 php_is_type 。它的定义如下:
#define INTERNAL_FUNCTION_PARAM_PASSTHRU execute_data, return_value
  • 函数 php_is_type 的定义如下:
static inline void php_is_type(INTERNAL_FUNCTION_PARAMETERS, int type)
{zval *arg;ZEND_PARSE_PARAMETERS_START(1, 1)Z_PARAM_ZVAL(arg)ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);if (Z_TYPE_P(arg) == type) {if (type == IS_RESOURCE) {const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(arg));if (!type_name) {RETURN_FALSE;}}RETURN_TRUE;} else {RETURN_FALSE;}
}
  • 前面几行是参数解析部分
ZEND_PARSE_PARAMETERS_START(1, 1)Z_PARAM_ZVAL(arg)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
  • 随后通过 Z_TYPE_P(arg) 获取变量的类型,再让其结果和 IS_ARRAY 判等。如果为真,则表示变量是数组,否则不是。
  • Z_TYPE_P 的作用很明显,就是获取变量的类型,这个宏展开后如下:
static zend_always_inline zend_uchar zval_get_type(const zval* pz) {return pz->u1.v.type;
}
  • 其中的 pz ,就是 zval 指针, zval 就是 经常提到的 _zval_struct:
struct _zval_struct {zend_value        value;            /* 值 */union {struct {ZEND_ENDIAN_LOHI_3(zend_uchar    type,         /* 类型 */zend_uchar    type_flags,union {uint16_t  call_info;    /* call info for EX(This) */uint16_t  extra;        /* not further specified */} u)} v;uint32_t type_info;} u1;union {uint32_t     next;                 /* hash 碰撞时用到的链表 */uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */uint32_t     opline_num;           /* opline number (for FAST_CALL) */uint32_t     lineno;               /* 行号 (ast 节点中) */uint32_t     num_args;             /* 参数数量 for EX(This) */uint32_t     fe_pos;               /* foreach 时的所在位置 */uint32_t     fe_iter_idx;          /* foreach iterator index */uint32_t     access_flags;         /* 类时的访问权限标志位 */uint32_t     property_guard;       /* single property guard */uint32_t     constant_flags;       /* constant flags */uint32_t     extra;                /* 保留字段 */} u2;
};
  • 不做深入介绍了。接续看 php_is_type
  • 在判断类型时,有个地方比较蹊跷: if (type == IS_RESOURCE) {
  • 为何这里要判断是否是资源类型?

延伸资源类型

  • 这里延伸一下,如果用 php_is_type 判断的是资源类型
  • 这里会调用 const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(arg));
  • 其中有 zend_rsrc_list_get_rsrc_type 的调用,其实现如下:
const char *zend_rsrc_list_get_rsrc_type(zend_resource *res)
{zend_rsrc_list_dtors_entry *lde;lde = zend_hash_index_find_ptr(&list_destructors, res->type);if (lde) {return lde->type_name;} else {return NULL;}
}
  • 有一个叫做 list_destructors 的静态变量,它的作用如下

    list_destructors 是一个全局静态 HashTable,资源类型注册时,将一个 zval 结构体变量 zv 存放入 list_destructors 的 arData 中,而 zv 的 value.ptr 却指向了 zend_rsrc_list_dtors_entry *lde ,lde中包含的该种资源释放函数指针、持久资源的释放函数指针,资源类型名称,该资源在 hashtable 中的索引依据 (resource_id)等。 --来源于“PHP7 使用资源包裹第三方扩展原理分析”

  • 也就是说,创建了一个资源类型R1时,就会向 list_destructors 中存入一份 zend_rsrc_list_dtors_entry ,其中包含了该资源R1的一些信息
  • 这里的 zend_hash_index_find_ptr 就是找到资源对应的 zend_rsrc_list_dtors_entry ,从而取其中的 lde->type_name
  • 如果 type 成员是存在的,则说明是资源类型。

总结

  • PHP 中使用 is_* 系列判断类型的函数,大部分都是通过变量底层 zval 中的 u1.v.type 来判断类型值
  • 如果是资源类型,需要通过 list_destructors 查询对应的资源类型是否存在,如果存在,说明资源句柄是可以正常使用的。

参考资料

  • https://www.jianshu.com/p/5956b4cfca17
  • PHP7扩展开发之依赖其他扩展
    • https://www.bo56.com/php7%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E4%BE%9D%E8%B5%96%E5%85%B6%E4%BB%96%E6%89%A9%E5%B1%95/
  • PHP7 使用资源包裹第三方扩展原理分析
    • https://segmentfault.com/a/1190000010185347

转载于:https://www.cnblogs.com/ishenghuo/p/11067978.html

PHP 源码 —— is_array 函数源码分析相关推荐

  1. is array php,PHP 源码 — is_array 函数源码分析

    php 中的 is_array php 中的 is_array,它的签名是 is_array ( mixed $var ) : bool 实现的源码 在\ext\standard\type.c中可以找 ...

  2. 【SA8295P 源码分析】22 - QNX Ethernet MAC 驱动 之 emac_entry / emac_attach 函数源码分析

    [SA8295P 源码分析]22 - QNX Ethernet MAC 驱动 之 emac_entry / emac_attach 函数源码分析 一.EMAC:libdevnp-emac-eth.so ...

  3. 【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )

    文章目录 一.do_mmap 函数执行流程 二.do_mmap 函数源码 调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 & ...

  4. 【Linux 内核】实时调度类 ⑦ ( 实时调度类核心函数源码分析 | dequeue_task_rt 函数 | 从执行队列中移除进程 )

    文章目录 一.dequeue_task_rt 函数 ( 从执行队列中移除进程 ) 二.update_curr_rt 函数 ( 更新调度信息 ) 本篇博客中 , 开始分析 struct sched_cl ...

  5. 【Linux 内核】实时调度类 ⑥ ( 实时调度类核心函数源码分析 | 插入进程到执行队列 | 从执行队列中选择优先级最高的进程 )

    文章目录 一.enqueue_task_rt 函数 ( 插入进程到执行队列 ) 二.pick_next_task_rt 函数 ( 从执行队列中选择优先级最高的进程 ) 本篇博客中 , 开始分析 str ...

  6. 【Linux 内核 内存管理】物理分配页 ⑨ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | retry 标号代码分析 )

    文章目录 一.retry 标号代码分析 二.retry 标号完整代码 在 [Linux 内核 内存管理]物理分配页 ② ( __alloc_pages_nodemask 函数参数分析 | __allo ...

  7. 【Linux 内核 内存管理】物理分配页 ⑦ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 判断页阶数 | 读取 mems_allowed | 分配标志位转换 )

    文章目录 一.__alloc_pages_slowpath 慢速路径调用函数 二.判断页阶数 三.读取进程 mems_allowed 成员 四.分配标志位转换 五.__alloc_pages_slow ...

  8. 【Linux 内核 内存管理】物理分配页 ⑧ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 获取首选内存区域 | 异步回收内存页 | 最低水线也分配 | 直接分配 )

    文章目录 一.获取首选内存区域 二.异步回收内存页 三.最低水线也分配 四.直接分配内存 在 [Linux 内核 内存管理]物理分配页 ② ( __alloc_pages_nodemask 函数参数分 ...

  9. 【Android 逆向】ART 脱壳 ( dex2oat 脱壳 | aosp 中搜索 dex2oat 源码 | dex2oat.cc#main 主函数源码 )

    文章目录 前言 一.搜索 dex2oat 源码 二.dex2oat.cc#main 主函数源码 前言 在 [Android 逆向]ART 脱壳 ( DexClassLoader 脱壳 | exec_u ...

最新文章

  1. 78行Python代码帮你复现微信撤回消息!
  2. linux连sql server
  3. 交换排序之——冒泡排序(c/c++)
  4. 基于php构建APi流程,php – 如何构建一个RESTful API?
  5. 数字组合(信息学奥数一本通-T1291)
  6. node 常用的一些终端的命令的快捷键
  7. 中国创客面临无限挑战
  8. type=file的未选择任何文件修改_Excel基础—文件菜单之创建保存
  9. seaJS 模块加载过程分析
  10. java中ascii码值_java中的ASCII码值
  11. ubuntu 自动登录账户_Ubuntu如何启用root默认自动登录
  12. 书评精益创业-新创企业的成长思维 (上)
  13. win7_64位下部署Apache+Mysql5.7.19+Php7+Snipe-IT
  14. 组装微型计算机需要哪些硬件设备,我们需要哪些配件组装电脑
  15. 【持续更新】2007-2022年英伟达历代桌面Tesla显卡列表,Tesla显卡发布日期
  16. 【spark】RDD数据源
  17. 读明朝那些事儿有感:书生的骨
  18. WPF ListBox颜色交替及以击事件实现
  19. 如何从Rstudio中导出合适的图片?
  20. STAC: A Simple Semi-Supervised Learning Framework for Object Detection

热门文章

  1. linux阿波罗配置文件放在哪,Apollo阿波罗配置中心
  2. python 回声程序_一种回声消除系统及回音消除方法与流程
  3. mongodb 3.4 安装_Python数据分析及可视化实例之CentOS7.2+MongoDB V3.4 安装
  4. VS编辑器 设置智能提示
  5. 【GAN优化】GAN优化专栏栏主小米粥自述,脚踏实地,莫问前程
  6. 辽宁省风力发电行业“十四五”前景规划及竞争策略分析报告2022-2028年版
  7. 全球与中国智慧物流市场”十四五“发展状况及投资前景规划报告2021-2027年版
  8. vc6.0快捷键大全- -
  9. 【LeetCode】【数组归并】Merge k Sorted Lists
  10. 【MySQL】玩转定时器