php 源码函数

在PHP中,函数分为俩种,

  • 一种是zend_internal_function, 这种函数是由扩展或者Zend/PHP内核提供的,用’C/C++’编写的,可以直接执行的函数。
  • 另外一种是zend_user_function, 这种函数呢,就是我们经常在见的,用户在PHP脚本中定义的函数,这种函数最终会被ZE翻译成opcode array来执行

查看zend_compile.h,我们可以找到如下的3个结构:

typedef struct _zend_internal_function {

  /* Common elements */

  zend_uchar type;

  char * function_name;

  zend_class_entry *scope;

  zend_uint fn_flags;

  union _zend_function *prototype;

  zend_uint num_args;

  zend_uint required_num_args;

  zend_arg_info *arg_info;

  zend_bool pass_rest_by_reference;

  unsigned char return_reference;

  /* END of common elements */

  void (*handler)(INTERNAL_FUNCTION_PARAMETERS);

    struct _zend_module_entry *module;

} zend_internal_function;

struct _zend_op_array {

  /* Common elements */

  zend_uchar type;

  char *function_name;

  zend_class_entry *scope;

  zend_uint fn_flags;

  union _zend_function *prototype;

  zend_uint num_args;

  zend_uint required_num_args;

  zend_arg_info *arg_info;

  zend_bool pass_rest_by_reference;

  unsigned char return_reference;

  /* END of common elements */

  zend_uint *refcount;

  zend_op *opcodes;

  zend_uint last, size;

  zend_compiled_variable *vars;

  int last_var, size_var;

  zend_uint T;

  zend_brk_cont_element *brk_cont_array;

  zend_uint last_brk_cont;

  zend_uint current_brk_cont;

  zend_try_catch_element *try_catch_array;

  int last_try_catch;

  /* static variables support */

  HashTable *static_variables;

  zend_op *start_op;

  int backpatch_count;

  zend_bool done_pass_two;

  zend_bool uses_this;

  char *filename;

  zend_uint line_start;

  zend_uint line_end;

  char *doc_comment;

  zend_uint doc_comment_len;

  void *reserved[ZEND_MAX_RESERVED_RESOURCES];

};

typedef union _zend_function {

  zend_uchar type; /* MUST be the first element of this struct! */

  struct {

    zend_uchar type; /* never used */

    char *function_name;

    zend_class_entry *scope;

    zend_uint fn_flags;

    union _zend_function *prototype;

    zend_uint num_args;

    zend_uint required_num_args;

    zend_arg_info *arg_info;

    zend_bool pass_rest_by_reference;

    unsigned char return_reference;

  } common;

  zend_op_array op_array;

  zend_internal_function internal_function;

} zend_function;

第一个结构,定义了zend_internal_function, 当PHP启动的时候 ,它会遍历每个载入的扩展模块,然后将模块中function_entry中指明的每一个函数, 创建一个zend_internal_function结构, 并将type置为ZEND_INTERNAL_FUNCTION(见下表), 将这个结构填入全局的函数表(一个HashTable);

  #define ZEND_INTERNAL_FUNCTION 1

  #define ZEND_USER_FUNCTION 2

  #define ZEND_OVERLOADED_FUNCTION 3

  #define ZEND_EVAL_CODE 4

  #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5

第二个结构,op_array, 这个结构很重要, 因为:

     extern ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);

也就是说,我们编写的PHP脚本,都会被ZE翻译成op_array, 最后交由zend_execute执行。

另外,在ZE中,用户定义的函数(userland function), 也会被翻译成一个op_array, 并填入全局函数表中。这个时候scope,function_name都不为空。而对于在全局作用域的直接代码来说,最后的op_array的scope为全局,function_name为空。

第三个结构, 很有趣, 要理解这个结构,首先你要理解他的设计目标: zend_internal_function, zend_function,zend_op_array可以安全的互相转换(The are not identical structs, but all the elements that are in “common” they hold in common, thus the can safely be casted to each other);

具体来说,当在op code中通过ZEND_DO_FCALL调用一个函数的时候,ZE会在函数表中,根据名字(其实是lowercase的函数名字,这也就是为什么PHP的函数名是大小写不敏感的)查找函数, 如果找到,返回一个zend_function结构的指针(仔细看这个上面的zend_function结构), 然后判断type,如果是ZEND_INTERNAL_FUNCTION, 那么ZE就调用zend_execute_internal,通过zend_internal_function.handler来执行这个函数, 如果不是,就调用zend_execute来执行这个函数包含的zend_op_array.

时间: 2024-10-27 06:13:07

php 源码函数的相关文章

关于追踪qemu 源码函数路径的一个方法

这阵子一直在研究qemu 磁盘io路径的源码,发现直接看代码是意见非常低效率的事情,qemu是一个比较庞大的家伙(源码部分大概154MB,完全由C语言来完成),整个结构也都非常地复杂,所以从代码上研究qemu最好的办法只有debug之.不断地收集更多的debug信息去获取源码所蕴含的道理. 很多人第一反应可能就是使用一些类似与Eclipse, gdb 这一类强大的debugger,我当然也不例外,在经过一个上午究竟该使用Eclipse还是gdb的思想斗争的私人情绪之后,我才恍然明白,原来我两个工

使用linux 版vscode 查看linux内核源码函数跳转比较慢的问题

在使用 deepin  +  vscode 查看linux源码时,发现比较恶心的问题,跳转到指定函数特别慢,偶尔还跳转不过去,在vscode 中安装一个插件就好了 1. vscode 安装插件名:C/C++ GNU Global 2. 在deepin中安装一个软件:sudo apt install global 3. 在deepin终端中使用 which global 查看global的安装路径  /usr/bin/global 4. 将这个路径配置到vscode 中 "gnuGlobal.gl

fork()相关的源码解析

fork()的真正执行采用的是do_fork()函数,所以下文将从do_fork()函数对fork()进行源码解析.下图是do_fork()的源码函数设计: 从上图我们可以看到do_fork()涉及到众多的参数.所以在进入do_fork函数进行分析之前,很有必要了解一下它的参数. clone_flags:克隆标识: * * cloning flags: */#define CSIGNAL 0x000000ff /* signal mask to be sent at exit *//** * 共

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

CI框架源码阅读笔记3 全局函数Common.php

从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap引导文件都会最先引入全局函数,以便于之后的处理工作). 打开Common.php中,第一行代码就非常诡异: if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 上一篇(CI框架源码阅读笔记2 一切的入口 index

菜鸟nginx源码剖析 框架篇(一) 从main函数看nginx启动流程(转)

俗话说的好,牵牛要牵牛鼻子 驾车顶牛,处理复杂的东西,只要抓住重点,才能理清脉络,不至于深陷其中,不能自拔.对复杂的nginx而言,main函数就是“牛之鼻”,只要能理清main函数,就一定能理解其中的奥秘,下面我们就一起来研究一下nginx的main函数. 1.nginx的main函数解读 nginx启动显然是由main函数驱动的,main函数在在core/nginx.c文件中,其源代码解析如下,涉及到的数据结构在本节仅指出其作用,将在第二节中详细解释. nginx main函数的流程图如下:

jQuery-1.9.1源码分析系列(十六)ajax——ajax处理流程以及核心函数

先来看一看jQuery的ajax核心处理流程($.ajax) a. ajax( [url,] options )执行流程 第一步,为传递的参数做适配.url可以包含在options中 //传递的参数只是一个对象 if ( typeof url === "object" ) { options = url; url = undefined; } //options强制转成对象 options = options || {}; 第二步,创建一些变量,比较重要的是:创建最终选项对象s.全局事

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html 在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup.在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdlin