PHP内核介绍及扩展开发指南—高级主题

简介:

1.1     使用数组

曾讲到,PHP数组本质上就是个HashTable,因此访问数组就是对HashTable进行操作,Zend为我们提供的一组数组函数也只是对HashTable操作进行了简单包装而已。

来看创建数组,由于数组也是存在于zval里的,因此要先用MAKE_STD_ZVAL()宏创建一个zval,之后调用如下宏将其转化为一个空数组:

array_init(zval*)

接下来是朝数组中添加元素,这对关联数组元素和非关联数组元素要采用不同操作。

 

1.1.1 关联数组元素

关联数组采用char*作为key,zval*作为value,可以使用如下宏将已有的zval加入数组或者更新已有元素:

int add_assoc_zval(zval *arr, char *key, zval *value)

需要特别注意的是,Zend不会复制zval,只会简单的储存其指针,并且不关心任何引用计数,因此不能将其他变量的zval或者是栈上的zval传给它,只能用MAKE_STD_ZVAL()宏构建。

Zend为常用的类型定义了相应的API,以简化我们的操作:

add_assoc_long(zval *array, char *key, long n);
add_assoc_bool(zval *array, char *key, int b);
add_assoc_resource(zval *array, char *key, int r);
add_assoc_double(zval *array, char *key, double d);
add_assoc_string(zval *array, char *key, char *str, int duplicate);
add_assoc_stringl(zval *array, char *key, char *str, uint length, int duplicate);
add_assoc_null(zval *array, char *key);

当函数发现目标元素已经存在时,会首先递减其原zval的refcount,然后才插入新zval,这就保证了原zval引用信息的正确性。这种行为是通过HashTable.pDestructor(参见1.2.1)实现的,每次删除一个元素时,HashTable都将对被删元素调用这个函数指针,而数组为其HashTable设置的函数指针就是用来处理被删除zval的引用信息。

另外,查看这些函数的源代码可以发现一个有意思的现象,它们没有直接使用HashTable操作,而是使用变量符号表操作,可见关联数组和变量符号表就是一种东西。

Zend没有提供删除和获取数组元素的函数,此类操作只能使用HashTable函数或者是2.6节的变量符号表操作。

1.1.2非关联数组元素

非关联数组没有key,使用index作为hash,相应函数和上面关联数组的十分类似:

add_index_zval(zval *array, uint idx, zval *value);
add_index_long(zval *array, uint idx, long n);
add_index_bool(zval *array, uint idx, int b);
add_index_resource(zval *array, uint idx, int r);
add_index_double(zval *array, uint idx, double d);
add_index_string(zval *array, uint idx, char *str, int duplicate);
add_index_stringl(zval *array, uint idx, char *str, uint length, int duplicate);
add_index_null(zval *array, uint idx);

如果只是想插入值,而不指定index的话,可以使用如下函数:

add_next_index_zval(zval *array, zval *value);
add_next_index_long(zval *array, long n);
add_next_index_bool(zval *array, int b);
add_next_index_resource(zval *array, int r);
add_next_index_double(zval *array, double d);
add_next_index_string(zval *array, char *str, int duplicate);
add_next_index_stringl(zval *array, char *str, uint length, int duplicate);
add_next_index_null(zval *array);

1.2      使用资源

1.2.1  注册资源类型

1.1.1节曾经提到,所谓资源就是内部数据的handle(但是这句话并不全对),使用资源是比较简单的,首先是注册一个资源类型:

int zend_register_list_destructors_ex(
rsrc_dtor_func_t ld,
rsrc_dtor_func_t pld,
char *type_name,
int module_number);

第一个参数是函数指针,当资源不再被使用或者模块将被卸载时,Zend使用它来销毁资源,稍候再作介绍;第二个参数和第一个类似,只是它被用来销毁持久性资源(*);type_name是资源名称,用户可以使用var_dump函数来读取;module_number是模块号,在启动函数中可以获取该值。

注册过程其实就是将我们传入的参数放到一个内部数据结构,然后把这个数据结构放入一个没有使用key的HashTable里,该函数返回的值,也就是所谓“资源类型id”,其实就是HashTable的index。

1.2.1  注册资源

注册完资源类型后,就可以注册一个该类型的资源了:

 
  
  1. ZEND_REGISTER_RESOURCE(  
  2. rsrc_result,  
  3. rsrc_pointer,  
  4. rsrc_type) 
src_pointer是个指针类型,就是你的资源的handle, 通常是指向内部数据的指针,当然也可以是index或者其它标志符;rsrc_type是上面获取的资源类型id;rsrc_result是个已有的zval,注册完成后,资源的id就被放入该zval,同时其type也被设为IS_RESOURCE,通常是传入return_value,以将资源返回给用户。

在内部,Zend使用如下数据结构表示一个资源:

 
  
  1. typedef struct _zend_rsrc_list_entry {  
  2.     void *ptr;  
  3.     int type;  
  4.     int refcount;  
  5. } zend_rsrc_list_entry; 
ptr和type就是我们在上面传入的参数;refcount是引用计数,由Zend维护,当引用减到0时,Zend会销毁该资源。不出所料的是,这个数据结构也被组织在一个HashTable里,并且没有使用key,仅仅使用index——这就是zval里存放的东西。现在资源的整个脉络已经清晰:通过zval可以获得资源id,通过资源id可以获得资源handle和资源类型id,通过资源类型id可以获得资源的销毁函数。
现在讲一下销毁函数:
 
  
  1. typedef void (*rsrc_dtor_func_t)(  
  2. zend_rsrc_list_entry *rsrc  
  3. TSRMLS_DC); 
rsrc是需要被销毁的资源,我们在函数的实现中可以通过它获得资源的handle,并且加以处理,比如释放内存块、关闭数据库连接或是关闭文件描述符等。

1.2.3  获取资源

当创建了资源后,用户通常都要调用创建者提供的函数来操作资源,此时我们需要从用户传入的zval中取出资源:

 
  1. ZEND_FETCH_RESOURCE(  
  2. rsrc,  rsrc_type,  
  3. passed_id, default_id,  
  4. resource_type_name, resource_type) 

首个参数用于接收handle值,第二个参数是handle值的类型,这个函数会扩展成“rsrc = (rsrc_type) zend_fetch_resource(…)”,因此应该保证rsrc是rsrc_type类型的;passed_id是用户传入的zval,这里使用zval**类型,函数从中取得资源id;default_id用来直接指定资源id,如果该值不是-1,则使用它,并且忽略passed_id,所以通常应该使用-1;resource_type_name是资源名称,当获取资源失败时,函数使用它来输出错误信息;resource_type是资源类型,如果取得的资源不是该类型的,则函数返回NULL,这用于防止用户传入一个其他类型资源的zval。

不过,这个宏确实比较难用,用其底层的宏反倒更加容易些:

 
  1. zend_list_find(id, type) 

id是要查找的资源id;type是int*类型,用于接收取出的资源的类型,可以用它来判断这是不是我们想要的资源;函数最后返回资源的handle,失败返回NULL。

1.2.4  维护引用计数

通常,当用户对资源类型的PHP变量执行赋值或是unset之类操作时,Zend会自动维护资源的引用计数。但有时,我们也需要手动进行,比如我们要复用一个数据库连接或者用户调用我们提供的close操作关闭一个文件,此时可以使用如下宏:

 
  1. zend_list_addref(id)  
  2. zend_list_delete(id) 

id是资源id,这两个宏分别增加和减少目标资源的引用计数,第二个宏还会在引用计数减到0时,调用先前注册的函数销毁资源。

 










本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/743769,如需转载请自行联系原作者

相关文章
|
1月前
|
存储 缓存 自然语言处理
深入PHP内核:理解Opcode缓存对性能的影响
【4月更文挑战第25天】 在提升PHP应用性能的众多策略中,Opcode缓存技术因其显著的效果和较低的复杂度而备受开发者青睐。本文将深入探讨Opcode缓存机制,解析其对PHP执行效率的提升原理,并通过实验数据展示启用Opcode缓存前后的性能差异。我们还将讨论几种流行的Opcode缓存工具,如APC、OpCache与APCu,并评估它们的优劣及适用场景,帮助开发者根据不同的项目需求做出合适的选择。通过本文,读者不仅能够了解Opcode缓存的工作原理,还能学会如何在实际项目中应用这一技术以优化PHP应用程序的性能。
|
1月前
|
存储 缓存 自然语言处理
深入PHP内核:理解Opcode缓存与性能优化
【5月更文挑战第14天】 在动态语言的世界里,PHP一直因其高性能的执行效率和广泛的社区支持而备受青睐。随着Web应用的复杂性增加,对性能的要求也越来越高。本文将探讨PHP的Opcode缓存机制,解析其对性能提升的贡献,并展示如何通过配置和使用不同的Opcode缓存方案来进一步优化PHP应用的性能。我们将深入到PHP的核心,了解Opcode是如何生成的,以及它如何影响最终的执行效率。
|
12天前
|
存储 PHP 开发者
PHP的魔法:从基础到高级
【6月更文挑战第7天】本文将带你走进PHP的世界,从基础语法到高级特性,一步步揭示PHP的魔法。我们将通过实例和代码片段,深入探讨PHP的核心概念,包括变量、数据类型、控制结构、函数、类和对象等。无论你是初学者还是有经验的开发者,都能在这篇文章中找到有价值的信息。
18 7
|
15天前
|
Ubuntu 关系型数据库 MySQL
ubuntu apt 安装wordpress所需所有的 一键脚本 扩展您的PHP似乎没有安装运行WordPress所必需的MySQL扩展。
ubuntu apt 安装wordpress所需所有的 一键脚本 扩展您的PHP似乎没有安装运行WordPress所必需的MySQL扩展。
ubuntu apt 安装wordpress所需所有的 一键脚本 扩展您的PHP似乎没有安装运行WordPress所必需的MySQL扩展。
|
15天前
|
Ubuntu 中间件 Linux
linux php添加扩展zip libzip ZipArchive功能
linux php添加扩展zip libzip ZipArchive功能
|
20天前
|
存储 缓存 自然语言处理
深入PHP内核:Opcode缓存与性能优化
【5月更文挑战第31天】 在提升PHP应用性能的众多策略中,Opcode缓存技术以其显著的性能提升效果而广受关注。本文旨在深入探讨PHP的Opcode缓存机制,解析其对性能提升的影响,并讨论如何通过配置和优化实践来充分利用Opcode缓存。文章将首先介绍Opcode的概念及其在PHP执行过程中的作用,然后分析几种流行的Opcode缓存解决方案,最后提供针对性的优化建议,帮助开发者实现高效的PHP应用。
|
21天前
|
存储 缓存 PHP
深入PHP内核:理解Zend Engine与Opcode缓存
【5月更文挑战第30天】 在PHP的开发世界中,性能优化是一个永恒的话题。随着现代Web应用的复杂性日益增加,仅仅依靠代码层面的优化已经远远不够。本文将深入探讨PHP的执行心脏——Zend Engine,以及如何通过Opcode缓存机制提升PHP应用的执行效率。我们将透过对Zend Engine工作原理的分析,了解Opcode缓存的实现原理,并通过实例来展示其对性能提升的显著影响。
|
24天前
|
缓存 算法 PHP
深入PHP内核:探索高性能代码优化策略
【5月更文挑战第27天】 在本文中,我们将深入探讨PHP的内核机制,并分析如何通过理解其工作原理来优化我们的代码。文章将聚焦于几个关键领域,包括解释器执行流程、内存管理、以及代码编写最佳实践等。我们的目标是为开发者提供实用的指导,帮助他们写出更加高效和稳定的PHP应用程序。
|
30天前
|
存储 缓存 负载均衡
深入PHP内核:探索Opcode缓存对性能的影响
在现代Web开发中,提升应用性能始终是开发者追求的目标之一。PHP作为一种广泛使用的服务端脚本语言,其执行效率对网站性能有着直接的影响。本文将深入探讨PHP的Opcode缓存机制,分析Opcode缓存如何优化PHP代码执行流程,减少服务器资源消耗,并通过实验数据展示启用Opcode缓存对性能的具体影响。我们将比较不同的Opcode缓存方案,并讨论它们在实际项目中的适用场景与潜在限制。
|
1月前
|
存储 缓存 自然语言处理
深入PHP内核:理解OPcache的工作原理与优化实践
【5月更文挑战第6天】 在现代Web开发中,提升性能和响应速度是持续追求的目标。PHP作为一种广泛使用的服务端脚本语言,其执行效率至关重要。本文将深入探索PHP的OPcache(优化器缓存)组件,解析其如何改善PHP的性能表现。通过剖析OPcache的工作机制,我们将讨论有效的配置策略以及实践中的最佳优化方法,旨在帮助开发者充分理解并利用OPcache来提升应用性能。