php的扩展与嵌入--php扩展中的数组和哈希表2
接着上面一节,继续说php扩展中的数组与哈希表的api,这节主要是说
回调遍历函数正常遍历函数析构函数排序、对比、极值函数
Iteration by hash Apply:
对数组进行遍历,最简单的是使用一种与php语言中foreach语句功能类似的函数,zend_hash_apply,它接收一个回调函数,并将hashtable的每一个元素传递给它。
typedef int (*apply_func_t)(void *pDest TSRMLS_DC); void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC);
typedef int (*apply_func_arg_t)(void *pDest, void *argument TSRMLS_DC); void <strong>zend_hash_apply_with_argument</strong>(HashTable *ht, apply_func_arg_t apply_func, void *data TSRMLS_DC);
表 回调函数的返回值
Constant Meaning
ZEND_HASH_APPLY_KEEP 结束当前请求,进入下一个循环。与PHP语言forech语句中的一次循环执行完毕或者遇到continue关键字的作用一样。
ZEND_HASH_APPLY_STOP 跳出,与PHP语言forech语句中的break关键字的作用一样。
ZEND_HASH_APPLY_REMOVE 删除当前的元素,然后继续处理下一个。相当于在PHP语言中:unset($foo[$key]);continue;
对于一段简单的php遍历代码
<?php foreach($arr as $val) { echo "The value is: $val\n"; } ?>
int php_sample_print_zval(zval **val TSRMLS_DC) { //重新copy一个zval,防止破坏原数据 zval tmpcopy = **val; zval_copy_ctor(&tmpcopy); //转换为字符串 INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); //开始输出 php_printf("The value is: "); PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy)); php_printf("\n"); //毁尸灭迹 zval_dtor(&tmpcopy); //返回,继续遍历下一个~ return ZEND_HASH_APPLY_KEEP; }
遍历了一个名为arrht,元素类型是zval*的哈希表。
注意保存在哈希表中的并不是元素,而是指针,也就是一个zval**.在复制的时候也是复制指针的,哈希表本身不会动内容的。
为了能够在循环的时候既接受到值,也接收到key,第三种形式zend_hash_apply():zend_hash_apply_with_arguments()
<?php foreach($arr as $key => $val) { echo "The value of $key is: $val\n"; } ?>
int php_sample_print_zval_and_key(zval **val, int num_args, va_list args, zend_hash_key *hash_key) { /* 复制zval从而使得原来的内容被保存下来 */ zval tmpcopy = **val; /* tsrm_ls is needed by output functions */ TSRMLS_FETCH(); zval_copy_ctor(&tmpcopy); /* Reset refcount & Convert */ INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); /* 输出 */ php_printf("The value of "); if (hash_key->nKeyLength) { /* 如果是字符串类型的key */ PHPWRITE(hash_key->arKey, hash_key->nKeyLength); } else { /* 如果是数字类型的key */ php_printf("%ld", hash_key->h); } php_printf(" is: "); PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy)); php_printf("\n"); /* Toss out old copy */ zval_dtor(&tmpcopy); /* continue; */ return ZEND_HASH_APPLY_KEEP; }
执行遍历: zend_hash_apply_with_arguments(arrht, php_sample_print_zval_and_key, 0); 当我们检查这个hash_key是字符串类型还是数字类型时,是通过nKeyLength属性来检测的,而不是arKey属性。这是因为内核有时候会留在arKey属性里些脏数据,但nKeyLength属性是安全的,可以安全的使用。甚至对于空字符串索引,它也照样能处理。比如:$foo[''] ="Bar";索引的值是NULL字符,但它的长度却是包括最后这个NULL字符的,所以为1。
Iteration by move forward 不用callback也可以实现哈希表遍历。这时候用的是哈希表的内部指针。
在用户空间里有很多可用的函数:
<?php $arr = array('a'=>1, 'b'=>2, 'c'=>3); reset($arr); while (list($key, $val) = each($arr)) { /* Do something with $key and $val */ } reset($arr); $firstkey = key($arr); $firstval = current($arr); $bval = next($arr); $cval = next($arr); ?>
* /* reset() */ void zend_hash_internal_pointer_reset(HashTable *ht); /* key() */ int zend_hash_get_current_key(HashTable *ht, char **strIdx, unit *strIdxLen, ulong *numIdx, zend_bool duplicate); * /* current() */ int zend_hash_get_current_data(HashTable *ht, void **pData); * /* next()/each() */ int zend_hash_move_forward(HashTable *ht); * /* prev() */ int zend_hash_move_backwards(HashTable *ht); * /* end() */ void zend_hash_internal_pointer_end(HashTable *ht); * /* Other... */ int zend_hash_get_current_key_type(HashTable *ht); int zend_hash_has_more_elements(HashTable *ht);
each()跟next步骤一样,但是又调用并返回了zend_hash_get_current_key()
所以下面给出了不用回调函数的哈希表遍历方法:
void php_sample_print_var_hash(HashTable *arrht) { for(zend_hash_internal_pointer_reset(arrht); zend_hash_has_more_elements(arrht) == SUCCESS; zend_hash_move_forward(arrht)) { char *key; uint keylen; ulong idx; int type; zval **ppzval, tmpcopy; type = zend_hash_get_current_key_ex(arrht, &key, &keylen, &idx, 0, NULL);//获得返回的key的类型。这个类型可能有三种 if (zend_hash_get_current_data(arrht, (void**)&ppzval) == FAILURE) {//获得当前索引所指的数据值 /* Should never actually fail * since the key is known to exist. */ continue; } /* 复制zval的值,从而原来的值不会被破坏掉 */ tmpcopy = **ppzval; zval_copy_ctor(&tmpcopy); /* 重新设定refcount 并且转换 */ INIT_PZVAL(&tmpcopy); convert_to_string(&tmpcopy); /* 输出 */ php_printf("The value of "); if (type == HASH_KEY_IS_STRING) { /* String Key / Associative */ PHPWRITE(key, keylen); } else { /* Numeric Key */ php_printf("%ld", idx); } php_printf(" is: "); PHPWRITE(Z_STRVAL(tmpcopy), Z_STRLEN(tmpcopy)); php_printf("\n"); /* 销毁原来的副本 */ zval_dtor(&tmpcopy); } }
HASH_KEY_IS_STRING 当前元素的索引是字符串类型的。therefore, a pointer to the element's key name will be populated into strIdx, and its length will be populated into stdIdxLen. If the duplicate flag is set to a nonzero value, the key will be estrndup()'d before being populated into strIdx. The calling application is expected to free this duplicated string.
HASH_KEY_IS_LONG 当前元素的索引是数字型的。
HASH_KEY_NON_EXISTANT HashTable中的内部指针已经移动到尾部,不指向任何元素。
Destruction 注意只有四种析构函数: 前两个是用来从哈希表中删掉单个元素的:
int zend_hash_del(HashTable *ht, char *arKey, uint nKeyLen); int zend_hash_index_del(HashTable *ht, ulong h);
分别对应字符串和数字索引的版本。
当一个元素从哈希表中移除的时候,哈希表的析构函数带着指向这个元素的指针被调用。
完全删除哈希表的时候:void zend_hash_clean(HashTable *ht);相当于是循环调用一下zend_hash_del。 调用下面这个函数除了执行clean之外,还会把zend_hash_init申请的空间都给搞掉:void zend_hash_destroy(HashTable *ht);
来看一个哈希表的生命周期就可以对整个过程有更清楚的认识:
int sample_strvec_handler(int argc, char **argv TSRMLS_DC) { HashTable *ht; /* 为哈希表分配空间 */ ALLOC_HASHTABLE(ht); /* 初始化哈希表的内部状态 */ if (zend_hash_init(ht, argc, NULL, ZVAL_PTR_DTOR, 0) == FAILURE) { FREE_HASHTABLE(ht); return FAILURE; } /* 把每个字符串变成zval* */ while (argc) { zval *value; MAKE_STD_ZVAL(value); ZVAL_STRING(value, argv[argc], 1); argv++; if (zend_hash_next_index_insert(ht, (void**)&value, sizeof(zval*)) == FAILURE) { /* 对于分配失败的情况应该跳掉 */ zval_ptr_dtor(&value); } } /* Do some work */ process_hashtable(ht); /* 毁坏哈希表 * 释放所有的分配的空旷 */ zend_hash_destroy(ht); /* Free the HashTable itself */ FREE_HASHTABLE(ht); return SUCCESS; }
Sorting, Comparing, and Going to the Extreme(s) 对于两个哈希表进行大小比较: typedef int (*compare_func_t)(void *a, void *b TSRMLS_DC); 这个函数就跟qsort一样,期待你自己的函数去比较a和b,返回-1 0 1
下面就是一个用大小比较的例子:
int zend_hash_minmax(HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC);
下面则给出一个更为具体的例子,通过不同的flag就可以控制到底是返回最大值还是最小值:
int fname_compare(zend_function *a, zend_function *b TSRMLS_DC) { return strcasecmp(a->common.function_name, b->common.function_name); } void php_sample_funcname_sort(TSRMLS_D) { zend_function *fe; if (zend_hash_minmax(EG(function_table), fname_compare, 0, (void **)&fe) == SUCCESS) { php_printf("Min function: %s\n", fe->common.function_name); } if (zend_hash_minmax(EG(function_table), fname_compare, 1, (void **)&fe) == SUCCESS) { php_printf("Max function: %s\n", fe->common.function_name); } }
还有一个进行哈希比较的函数: int zend_hash_compare(HashTable *hta, HashTable *htb,
compare_func_t compar, zend_bool ordered TSRMLS_DC); 先比较哈希表的个数,哪个多哪个大。 如果一样多的,就每个元素去比较。
另外还有一个专门的排序函数:
typedef void (*sort_func_t)(void **Buckets, size_t numBuckets, size_t sizBucket, compare_func_t comp TSRMLS_DC); int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compare_func, int renumber TSRMLS_DC);

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

PHP的SNMP扩展是一种使PHP能够通过SNMP协议与网络设备进行通信的扩展程序。使用该扩展可以方便地获取和修改网络设备的配置信息,例如路由器、交换机等设备的CPU、内存、网络接口等信息,也可以进行诸如开关设备端口等控制操作。本文将介绍SNMP协议的基础知识、PHP的SNMP扩展的安装方法以及如何在PHP中使用SNMP扩展进行网络设备的监控和控制。一、SN

PHP与HTML结合是网页开发中常见的一种技术,通过PHP可以在HTML文件中嵌入动态内容、实现辅助功能等,大大提高了网站的交互性和可定制性。本文将介绍三种嵌入代码的技巧,并提供具体的代码示例供参考。一、使用PHP标记嵌入代码最常见的方式是使用PHP标记()将PHP代码嵌入到HTML文件中,实现动态内容的显示。例如,可以使用PHP

从头到尾:如何使用php扩展cURL进行HTTP请求引言:在Web开发中,经常需要与第三方API或其他远程服务器进行通信。而使用cURL进行HTTP请求是一种常见而强大的方式。本文将介绍如何使用php扩展cURL来执行HTTP请求,并提供一些实用的代码示例。一、准备工作首先,确保php已安装cURL扩展。可以在命令行执行php-m|grepcurl查

要扩展PHP函数功能,可以使用扩展和第三方模块。扩展提供附加函数和类,可通过pecl包管理器安装和启用。第三方模块提供特定功能,可通过Composer包管理器安装。实践案例包括使用扩展解析复杂JSON数据和使用模块验证数据。

1.UncaughtError:Calltoundefinedfunctionmb_strlen();出现如上错误时,说明我们没装上mbstring扩展;2.进入PHP安装目录cd/temp001/php-7.1.0/ext/mbstring3.启动phpize(/usr/local/bin/phpize或/usr/local/php7-abel001/bin/phpize)命令来安装php扩展4../configure--with-php-config=/usr/local/php7-abel

如何使用极光推送扩展,在PHP应用中实现批量消息推送功能在移动应用的开发中,消息推送是一项非常重要的功能。极光推送是一种常用的消息推送服务,提供了丰富的功能和接口。本文将介绍如何使用极光推送扩展在PHP应用中实现批量消息推送功能。第一步:注册极光推送账号并获取API密钥首先,我们需要在极光推送官网(https://www.jiguang.cn/push)注册

PHP是一种流行的服务器端语言,可以用来开发Web应用程序和处理文件。PHP的ZipArchive扩展是一个强大的工具,可以在PHP中操作zip文件。在这篇文章中,我们将介绍如何使用PHP的ZipArchive扩展来创建、读取和修改zip文件。一、安装ZipArchive扩展在使用ZipArchive扩展之前,需要确保已经安装了这个扩展。安装方法如下:1.安

PHP的POSIX扩展是一组允许PHP与POSIX兼容操作系统进行交互的函数和常量。POSIX(PortableOperatingSystemInterface)是一组操作系统接口标准,旨在允许软件开发人员编写可在各种UNIX或UNIX类操作系统上运行的应用程序。本文将介绍如何使用PHP的POSIX扩展,包括安装和使用。一、安装PHP的POSIX扩展在
