百度工程师对PHP函数的实现原理及性能分析(1)
在任何语言中,函数是最基本的组成单元。PHP的功能是什么函数调用是如何实现的你对PHP函数的性能有什么建议本文将从原理出发,通过实际的性能测试来回答这些问题,以便在理解实现的同时更好地编写PHP程序,同时也将介绍一些常用的PHP函数。
PHP函数的分类
在PHP中,功能分为两大类:用户功能(内置函数)和内部功能(内置函数)。前者是一个数量的函数和方法,用户自定义程序,后者是各种库函数(如sprintf,array_push,等)由PHP本身提供。用户也可以通过扩展方法编写的库函数,这将在后面介绍。用户的功能,它可以分为功能(功能)和方法(类的方法)。本文对这三种功能分别进行了分析和测试。
PHP函数的实现
PHP函数是如何执行的,进程是什么
要回答这个问题,让我们看看PHP代码的执行过程。
从图1可以看出,PHP实现了一个典型的动态语言的实现过程:得到一段代码,通过词法分析、语法分析阶段,源程序会被翻译成指令(操作码),然后Zend虚拟机来执行这些指令完成操作。PHP本身是用C实现的,所以最后的电话也是一个事实上的功能,我们可以看到PHP作为开发软件。通过以上的介绍,不难看出,在PHP执行功能也翻译成操作码。每个函数调用实际上执行一个或多个指令。
对于每个功能,Zend是由以下描述的数据结构
复制代码代码如下所示:
_zend_function { typedef联盟
zend_uchar型;必须*本*结构的第一要素!
struct {
zend_uchar型从未使用; / * * /
char * function_name;
zend_class_entry *范围;
zend_uint fn_flags;
联盟_zend_function *原型;
zend_uint num_args;
zend_uint required_num_args;
zend_arg_info * arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
常见的};
zend_op_array op_array;
zend_internal_function internal_function;
zend_function };
_zend_function_state { typedef struct
* function_symbol_table哈希表;
zend_function *功能;
保留zend_max_reserved_resources } { void *;
zend_function_state };
类型指示函数的类型:用户功能,内置函数,重载函数。一般包含函数的基本信息,包括函数名、参数信息,功能标志(普通函数、静态方法,抽象方法)等。此外,对于用户的功能,还有一个功能,符号表,内部变量记录,等等,这将在后面详细介绍。function_table Zend维护全局,这是一个大的哈迪表。当一个函数被调用时,相应的zend_function发现首先根据函数名称的表。当一个函数调用,虚拟机会决定调用方法根据D不同类型和不同功能类型不同。
内置函数
内置函数本质上是一个真正的C函数。每一个内置函数,PHP将扩展到一个函数调用zif_xxxx最终编译,例如在我们共同的sprintf,对应的底层是zif_sprintf.when Zend被执行,如果发现它是一个内置的功能,这是一个简单的转发操作。
Zend提供了一系列的API调用,包括参数采集、数组运算、内存分配、等等。内置函数的参数的获取是通过zend_parse_parameters方法实现。对于数组,字符串和其他参数,可以实现浅拷贝,所以效率很高。可以说,PHP内置函数,效率几乎是对应的C函数一样,和唯一的前锋打超过一次。
内建函数是通过PHP动态加载,用户可以编写相应的根据自己的需要,这是我们经常谈论的about.zend提供延长使用一系列的API的扩展
用户功能
内置函数相比,自定义功能,用户通过PHP实现有完全不同的执行和实施原则。正如我们前面所提到的,我们知道php代码翻译成操作码和用户功能也不例外。事实上,每个功能对应的一组操作码,这是存储在zend_function.as结果的用户函数的调用最终是一套操作码执行。
局部变量的保持与递归实现
我们知道,函数递归是通过堆栈完成。在PHP中,也以类似的方式实现的。Zend分配一个主动的符号表(active_sym_table)每个PHP函数在当前函数记录所有局部变量的状态。所有的符号表被保持在堆栈的形式,每一次一个函数调用被调用时,一个新的符号表被分配到堆栈。当呼叫结束时,当前的符号表的堆栈。这样的状态保存和递归实现。
对于栈的维护,Zend被优化,静态数组的n个长度是预先分配的模拟堆栈。这种静态数组模拟动态数据结构的方法也在我们自己的程序中使用。这种方式避免了每个call.zend导致内存分配和毁灭只是滴符号表的数据清洗在当前栈顶在函数调用结束。由于静态数组的长度为n,一次函数调用水平大于n,将没有堆栈溢出。在这种情况下,Zend将摧毁符号表,所以它会导致大量的性能退化。在Zend,电流值为32,因此,当我们写的PHP程序,函数调用层次最好不要超过32。当然,如果它是一个Web应用程序,它本身可以调用层次结构的深度。
参数的传递和内置函数调用zend_parse_params来获得不同的参数,对采集参数的用户功能是通过指令来完成的。一个函数有几个参数对应的几个指令。具体到实施是一个普通的变量赋值,通过以上分析,我们可以看到,内置函数相比,它是自我维护的栈台,和每个指令的执行也是一个C函数。用户函数的性能相对较差,以后会有具体的比较分析。因此,如果一个函数有相应的PHP内置函数实现,不要自行重写函数来实现它。