1. PHP7底层开发原理入门
PHP7是目前使用最广泛的PHP版本之一,对于PHP语言的底层开发原理,多数开发者都有一些模糊的认知,没有具体的了解。在这篇文章中,我们将从零开始,带您学习PHP内核的设计与实现原理,让您对PHP底层的奥秘有更深入的了解。
2. PHP内核封装方式
在PHP7的开发过程中,PHP内核是以面向对象的封装方式来完成的,将相关的功能代码进行分组,封装在相应的PHP类中。若要获取相应的功能,只需要通过实例化相应的类,调用提供的API即可。
2.1 字符串的封装
PHP中的字符串是由多个字符构成的,我们可以通过类似于以下的方式来创建一个字符串:
$str = 'Hello World';
在PHP内核中,字符串类型的封装主要是通过PHP的zend_string结构体来完成的。zend_string定义如下:
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h;
size_t len;
char val[1];
};
可以看到,zend_string结构体定义了GC回收机制和具体的字符串值,其中GC回收机制实现了PHP内核对于内存的自动管理,大大减轻了开发者的工作负担。
2.2 数组的封装
PHP中的数组是一种非常常用的数据结构,用来存储多个相同类型的数据。在PHP7内核中,数组是由HashTable实现的。
以下是一个使用PHP数组的例子:
$arr = array('apple', 'banana', 'orange');
在PHP内核中,HashTable是一个键值对的结构,键值可以是任意类型,值也可以是任意类型。具体的HashTable结构体定义如下:
typedef struct _hashtable {
uint32_t nTableSize; /* 表的大小 */
uint32_t nTableMask; /* 用于遍历现有的哈希表,必须是power of 2 */
uint32_t nNumOfElements; /* 当·前哈希表中元素的数量 */
uint32_t nNextFreeElement; /* 未使用的最小索引 */
Bucket *pInternalPointer; /* 指向当前元素的指针 */
Bucket *pListHead; /* 指向 Bucket 数组的第一个双向链表 */
Bucket *pListTail; /* 指向 Bucket 数组的最后一个双向链表 */
Bucket **arBuckets; /* 哈希表 */
dtor_func_t pDestructor; /* 销毁函数指针 */
zend_bool persistent; /* 持久性 */
unsigned char nApplyCount; /* 递归计数器 */
zend_bool bApplyProtection; /* 避免哈希表在遍历时被修改 */
zend_bitset *pInternalPointerMap; /* 指向pInternalPointer的映射 */
unsigned char nIteratorsCount; /* 迭代器数量 */
} HashTable;
通过HashTable中的Bucket数组,我们可以获取到每个元素的键和值。这些键值对的插入和删除都是通过HashTable提供的API来实现的。
3. PHP内核的内存管理机制
PHP底层涉及到的内存管理主要有两种方式:
3.1 zend_mm机制
zend_mm机制是PHP内核中,较为常用且成熟的一种内存管理方式,主要目的在于减少内存申请的次数。对于可以重用的内存在zend_mm机制下会被缓存,以供后续使用。
3.2 GC回收机制
在高级编程语言中,内存管理是一项基本且重要的任务。PHP底层实现了自己独特的GC回收机制,减少了开发人员在代码中对于内存的控制,在减轻了人工负担的同时,也增加了代码的可读性。GC回收机制是在PHP底层的Zend Engine2中实现的,从原理上来看,Zend GC的逻辑是基于引用计数来实现的。
4. PHP7内核模块开发
PHP内核在实现模块化开发方面有着很高的自由度,可以通过动态链接库来实现自定义模块的开发。一般来说,PHP模块的开发遵循以下步骤:
4.1 定义模块
模块开发开始的第一步,就是需要在模块中定义模块本身的一些属性。我们可以通过zend_module_entry结构体来定义模块信息,下面是一个例子:
zend_module_entry mytest_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_MYTEST_EXTNAME,
NULL, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
PHP_MYTEST_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
4.2 PHP函数的定义
当模块被加载到PHP内核中后,模块暴露的函数也可以被调用。我们通过zend_function_entry来定义一个模块的函数:
const zend_function_entry mytest_functions[] = {
PHP_FE(mytest_hello, NULL)
PHP_FE_END
};
4.3 模块编译与安装
模块开发完成后,我们还需要将其编译成so库,然后将其安装到PHP的模块目录下,才能让PHP真正的使用它。PHP中提供了两个主要的工具用来编译模块: phpize和configure。
5. 结论
在本文章中,我们深入的研究了PHP内核底层开发的原理,从zend_string,HashTable的封装,zend_mm机制,GC回收机制,到模块的开发等多个方面都进行了介绍。希望本文能让您有更深入的了解,并且能更好地应用到实际的开发中。