PHP总结

简介

PHP作为一种优秀的脚本语言,从简单的“hello word”到各种框架的开发、架构的设计、性能优化,以及PHP模块的开发,涉及较广知识结构和跨度。PHP通过不断淬炼,PHP内核中涉及从脚本的编译解析到执行以及和Web服务器等的配合,内存管理,语法实现等。

SAPI

PHP总结_第1张图片

执行

PHP是一种基于C语言高级语言,作为一种解释型编程语言,能够好的进行跨平台开发。而C/C++在进行跨平台开发时需要重新编译、链接。

  • C程序只需通过一次编译之后生成机器码,具有较高的执行效率。
    PHP在每次执行都要经过编译,执行效率不高,但目前有一些拓展(APC等),将opcode缓存,从而不需要每次都进行编译。PHPZend引擎最主要的特性就是把 PHP的边解释边执行的运行方式改为先进行预编译(Compile),然后再执行(Execute)。这两者的分开给 PHP带来了革命性的变化:执行效率大幅提高;由于实行了功能分离,降低了模块间耦合度,可扩展性也大大增强。

PHP脚本执行流程 词法解析->语法解析->生成opcode->Zend执行
这里写图片描述
PHP总结_第2张图片
tip1: 在引擎初始化的时候,zend_execute和zend_compile_file会在引擎初始化的时候指向默认的方法。我们可以在编译和执行重写函数的指向,这样就为我们扩展引擎时留下了钩子。例如:vld将zend_execute和zend_compile_file指向自己对原始函数封装后的函数,添加了opcode信息的输出。

变量

  • PHP中变量并不区分类型,而是由底层对变量进行区分。

变量用 struct _zval_struct结构体来存储,值存在一个_zvalue_value union结构中。其中zvalue_value并不是一个结构体,为了节省内存使用的union来实现的,因为在同一时刻变量只能表示一种类型。其原型:

typedef union _zvalue_value{
    long lval;                  
    double dval;
    struct {
            char *val;
            int len;            //字符串的长度
        }str;
    HashTable *ht;              //保存数组
    zend_object_value obj;      //对象
}zvalue_value;

在PHP中数组是通过hash表数据结构来实现的,通过HashTable和Bucket来进行操作。
在HashTable中容量的扩增,始终调整为接近初始大小的2的整数次方。因为:
在选槽时,这里使用&操作而不是使用取模,这是因为是相对来说取模操作的消耗和按位与的操作大很多。
HashTable中

typedef struct bucket {
    ulong h;            // 对char *key进行hash后的值,或者是用户指定的数字索引值
    uint nKeyLength;    // hash关键字的长度,如果数组索引为数字,此值为0
    void *pData;        // 指向value,一般是用户数据的副本,如果是指针数据,则指向pDataPtr
    void *pDataPtr;     //如果是指针数据,此值会指向真正的value,同时上面pData会指向此值
    struct bucket *pListNext;   // 整个hash表的下一元素
    struct bucket *pListLast;   // 整个哈希表该元素的上一个元素
    struct bucket *pNext;       // 存放在同一个hash Bucket内的下一个元素
    struct bucket *pLast;       // 同一个哈希bucket的上一个元素
// 保存当前值所对于的key字符串,这个字段只能定义在最后,实现变长结构体
    char arKey[1];              

} Bucket; 

1.在Bucket中存储的是哈希值而不是哈希的索引。
2.上面结构体的最后一个字段用来保存key的字符串,而这个字段却申明为只有一个字符的数组, 其实这里是一种长见的变长结构体,主要的目的是增加灵活性。

函数

在生成中间代码时,已经统一了函数名全部为小写,表示函数的名称不是区分大小写的。

每个PHP脚本都有自己专属的全局符号表,而每个用户自定义的函数也有自己的符号表, 这个符号表用来存储在这个函数作用域下的属于它自己的变量。
当调用每个用户自定义的函数时, 都会为这个函数创建一个符号表,当这个函数返回时都会释放这个符号表。
参数的传递
第一步是SEND_VAR操作,函数调用是DO_FCALL,在此中间代码之前有一个SEND_VAR操作,此操作的作用是将实参传递给函数, 并且将它添加到函数栈中。
第二步是RECV操作。 RECV操作和SEND_VAR操作不同,它是归属于当前函数的操作,仅为此函数服务。 它的作用是接收SEND过来的变量,并将它们添加到当前函数的符号表。
匿名函数create_function函数的返回值: 函数返回一个唯一的字符串函数名。
该函数在定义了一个函数之后,给函数起了个名字,它将函数名的第一个字符变为了’\0’也就是空字符,用户代码中无法定义出这样的函数, 也就不存在命名冲突的问题了.

内存管理

  1. PHP底层对内存的管理,围绕着
    小块内存列表(free_buckets)、
    大块内存列表(large_free_buckets和
    剩余内存列表(rest_buckets)
    三个列表来分层进行的。
    PHP总结_第3张图片

  2. php申请流程
    PHP总结_第4张图片

  3. 垃圾回收
    PHP垃圾回收使用引用计数系统中的同步周期回收

你可能感兴趣的:(PHP)