首页 后端开发 php教程 php的扩展与嵌入--php扩展中的数组和哈希表1_PHP教程

php的扩展与嵌入--php扩展中的数组和哈希表1_PHP教程

Jul 13, 2016 am 10:42 AM
嵌入 扩展

在php中,数组的底层实现就是哈希表,都是以key-value的形式出现的。在php的Zend引擎中,针对不同的哈希表操作,都有着专门的对哈希表进行操作的api。


Creation

对于哈希表而言,每次初始化的方式都是一样的,都由下面这个函数zend_hash_init来完成:

int zend_hash_init(HashTable *ht, uint nSize,
    hash_func_t pHashFunction,
    dtor_func_t pDestructor, zend_bool persistent)
登录后复制
其中ht是指向哈希表的指针,既可以对一个已存在的hashtable变量取引用。也可以为新的hashtable申请内存。一般的方法就是:

ALLOC_HASHTABLE(ht),相当于ht = emalloc(sizeof(HashTable));。

nSize是哈希表的最大元素数,是为了提前申请好内存考虑的。如果它不是2的指数倍,会根据下式增长nSize = pow(2, ceil(log(nSize, 2)));,比如如果给了5,那么会增长到8.这个应该是为了内存管理比较方便所采用的机制。

pHashFunction属于以前版本的zend eigine函数,在新版本中一直设为NULL即可。

pDestructor指向当哈希表中的元素被删掉的时候(zend_hash_del() zend_hash_update())所调用的方法的入口,也就是一个相应的回调函数。假如说给定了method_name函数,那么在函数实现的时候:

void method_name(void *pElement)
pElement指向被删掉的元素

persistent这个是一个标志位,表示是否是持久型的哈希表,持久型的数据是独立于请求之外的,不会在RSHUTDOWN的时候被注销掉。但是如果设1的话,那么ht在申请内存的时候一定要使用pemalloc().

举个例子:在每个php请求生命周期中对symbol_table初始化的时候都会看到zend_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0);
每当unset的时候,相应的存储在哈希表中的zval*都被发送给zval_ptr_dtor()进行销毁。


Population:

有四种主要的插入和更新哈希表中数据的函数:

int zend_hash_add(HashTable *ht, char *arKey, uint nKeyLen,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_update(HashTable *ht, char *arKey, uint nKeyLen,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_index_update(HashTable *ht, ulong h,
                void *pData, uint nDataSize, void **pDest);
int zend_hash_next_index_insert(HashTable *ht,
                void *pData, uint nDataSize, void **pDest);
登录后复制
前两个函数添加带字符串索引的数据到hashtable中,比如php中$foo['bar'] = 'barvalue',那么在扩展中:

zend_hash_add(fooHashTbl, "bar", sizeof("bar"), &barZval, sizeof(zval*), NULL);

就把相应key值和对应的表值加入到了hashtable中去了。

add和update唯一的区别是如果key已经存在的话,add会失败的。

后两个函数是向ht中添加数字索引的数据。

zend_hash_next_index_insert()函数不需要索引值参数,而是自己直接计算出下一个数字索引值。

而如果想自己获得下一个元素的数字索引值也可以通过zend_hash_next_free_element()来获得索引。
ulong nextid = zend_hash_next_free_element(ht);
zend_hash_index_update(ht, nextid, &data, sizeof(data), NULL);
上面这段代码就相当于:

zend_hash_next_index_insert(HashTable *ht, &data,sizeof(data),NULL).

其中pDest参数可以用来存储新加入的元素的地址值。



Recall:查找

一般来说,有两种获得哈希表中数据的方法:

int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength,
                                        void **pData);
int zend_hash_index_find(HashTable *ht, ulong h, void **pData);
登录后复制

在下面的这个例子中可以更清楚的看到:

void hash_sample(HashTable *ht, sample_data *data1)
{
   sample_data *data2;
   ulong targetID = zend_hash_next_free_element(ht);//获取下一个索引的位置
   if (zend_hash_index_update(ht, targetID,
           data1, sizeof(sample_data), NULL) == FAILURE) {//把数据data1插入到哈希表的下一个索引的位置中去
       /* Should never happen */
       return;
   }
   if(zend_hash_index_find(ht, targetID, (void **)&data2) == FAILURE) {//利用id去寻找哈希表中的值,如果找到的话把值放在data2中。
       /* Very unlikely since we just added this element */
       return;
   }
   /* data1 != data2, however *data1 == *data2 */
}
登录后复制
除了获得哈希表中的值之外,有的时候更重要的是知道一些元素的存在:

int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLen);
int zend_hash_index_exists(HashTable *ht, ulong h);
登录后复制
分别针对字符串索引和数字的索引。返回的是1和0.
if (zend_hash_exists(EG(active_symbol_table),
                                "foo", sizeof("foo"))) {//确定活动的符号表中是否存在foo变量
    /* $foo is set */
} else {
    /* $foo does not exist */
}
登录后复制


Quick Population and Recall 当需要对同一个字符串的key进行许多操作的时候比如先检测有没有,然后插入再修改之类的,可以使用zend_get_hash_value来进行提速。这个函数的返回值可以和quick系列的函数使用,从而达到加速的目的。因为不需要再重复计算字符串的散列值,而是直接使用已有的散列值
ulong zend_get_hash_value(char *arKey, uint nKeyLen);
登录后复制
用这个返回值传给下面的quick系列函数就可以达到加速的目的:
int zend_hash_quick_add(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval,
    void *pData, uint nDataSize, void **pDest);
int zend_hash_quick_update(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval,
    void *pData, uint nDataSize, void **pDest);
int zend_hash_quick_find(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval, void **pData);
int zend_hash_quick_exists(HashTable *ht,
    char *arKey, uint nKeyLen, ulong hashval);
登录后复制

下面给出了一个在两个哈希表之间进行数据拷贝的例子:
void php_sample_hash_copy(HashTable *hta, HashTable *htb,
                    char *arKey, uint nKeyLen TSRMLS_DC)
{
    ulong hashval = zend_get_hash_value(arKey, nKeyLen);//获得用来加速的散列值hashval
    zval **copyval;
    if (zend_hash_quick_find(hta, arKey, nKeyLen,
                hashval, (void**)©val) == FAILURE) {//首先要在hta table里面找到相应的元素,并且存储在copyval中。
        /* arKey doesn't actually exist */
        return;
    }
    /* The zval* is about to be owned by another hash table */
    (*copyval)->refcount__gc++;//相应zval*变量的引用次数+1
    zend_hash_quick_update(htb, arKey, nKeyLen, hashval,
                copyval, sizeof(zval*), NULL);//把从hta中拿来的copyval放在htb里面。
}
登录后复制

注意并没有zend_hash_del函数。

Copy and Merging 有三个方法可以进行数据的拷贝,先来看第一个:
typedef void (*copy_ctor_func_t)(void *pElement);
void zend_hash_copy(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor,
            void *tmp, uint size);
登录后复制
在source中的每个元素都会被拷贝到target中.通过pCopyConstructor的处理可以使得在拷贝变量的时候对这些变量的ref_count进行加一的操作。target中原有的与source中索引位置相同的元素会被替换掉,而其他的元素则会被保留。
tmp这里放NULL,低版本才会用到。
size的话代表每个元素的大小,一般是sizeof(zval *)。
void zend_hash_merge(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor,
            void *tmp, uint size, int overwrite);
登录后复制
主要是多了一个overwrite的参数,如果非0,那就跟copy一样,如果是0,那就对于已经存在的元素就不会进行复制了。

下面的这一组函数允许使用一个归并的检查进行选择性的复制:
typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht,
    void *source_data, zend_hash_key *hash_key, void *pParam);
void zend_hash_merge_ex(HashTable *target, HashTable *source,
            copy_ctor_func_t pCopyConstructor, uint size,
            merge_checker_func_t pMergeSource, void *pParam);
登录后复制
pMergeSource回调函数使得可以选择性的进行合并,而不是全部合并,这个给人的感觉有点像c语言里面快速排序函数所留的函数入口,可以决定排序的方式。
下面给出了一个应用的例子:
zend_bool associative_only(HashTable *ht, void *pData,
            zend_hash_key *hash_key, void *pParam)
{
    /* True if there's a key, false if there's not */
    return (hash_key->arKey && hash_key->nKeyLength);//字符串类型的key,因为存在nKeyLength
}
void merge_associative(HashTable *target, HashTable *source)
{
    zend_hash_merge_ex(target, source, zval_add_ref,
                sizeof(zval*), associative_only, NULL);
}
登录后复制





















www.bkjia.comtruehttp://www.bkjia.com/PHPjc/635039.htmlTechArticle在php中,数组的底层实现就是哈希表,都是以key-value的形式出现的。在php的Zend引擎中,针对不同的哈希表操作,都有着专门的对哈希表进行...
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

php如何使用PHP的SNMP扩展? php如何使用PHP的SNMP扩展? Jun 02, 2023 am 10:22 AM

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

从头到尾:如何使用php扩展cURL进行HTTP请求 从头到尾:如何使用php扩展cURL进行HTTP请求 Jul 29, 2023 pm 05:07 PM

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

PHP与HTML结合:三种嵌入代码的技巧 PHP与HTML结合:三种嵌入代码的技巧 Mar 06, 2024 am 08:09 AM

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

PHP 函数的扩展和第三方模块 PHP 函数的扩展和第三方模块 Apr 13, 2024 pm 02:12 PM

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

CENTOS7下如何安装mbstring扩展? CENTOS7下如何安装mbstring扩展? Jan 06, 2024 pm 09:59 PM

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应用中实现批量消息推送功能 Jul 25, 2023 pm 08:07 PM

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

php如何使用PHP的ZipArchive扩展? php如何使用PHP的ZipArchive扩展? Jun 02, 2023 am 08:13 AM

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

php如何使用PHP的POSIX扩展? php如何使用PHP的POSIX扩展? Jun 03, 2023 am 08:01 AM

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

See all articles