php的hash算法介绍

Hash Table是PHP的核心,这话一点都不过分。

PHP的数组,关联数组,对象属性,函数表,符号表,等等都是用HashTable来做为容器的。

PHP的HashTable采用的拉链法来解决冲突, 这个自不用多说, 我今天主要关注的就是PHP的Hash算法, 和这个算法本身透露出来的一些思想。

PHP的Hash采用的是目前最为普遍的DJBX33A (Daniel J. Bernstein, Times 33 with Addition), 这个算法被广泛运用与多个软件项目,Apache, Perl和Berkeley DB等. 对于字符串而言这是目前所知道的最好的哈希算法,原因在于该算法的速度非常快,而且分类非常好(冲突小,分布均匀).

算法的核心思想就是:


代码如下:

hash(i) = hash(i-1) * 33 + str[i]

在zend_hash.h中,我们可以找到在PHP中的这个算法:

代码如下:

static inline ulong zend_inline_hash_func(char *arKey, uint nKeyLength)
{
    register ulong hash = 5381;

/* variant with the hash unrolled eight times */
    for (; nKeyLength >= 8; nKeyLength -=  {
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
        hash = ((hash << 5) + hash) + *arKey++;
    }
    switch (nKeyLength) {
        case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
        case 1: hash = ((hash << 5) + hash) + *arKey++; break;
        case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
    }
    return hash;
}

相比在Apache和Perl中直接采用的经典Times 33算法:

代码如下:

hashing function used in Perl 5.005:
  # Return the hashed value of a string: $hash = perlhash("key")
  # (Defined by the PERL_HASH macro in hv.h)
  sub perlhash
  {
      $hash = 0;
      foreach (split //, shift) {
          $hash = $hash*33 + ord($_);
      }
      return $hash;
  }

在PHP的hash算法中, 我们可以看出很处细致的不同.

首先, 最不一样的就是, PHP中并没有使用直接乘33, 而是采用了:


代码如下:

hash << 5 + hash

这样当然会比用乘快了.

然后, 特别要主意的就是使用的unrolled, 我前几天看过一片文章讲Discuz的缓存机制, 其中就有一条说是Discuz会根据帖子的热度不同采用不同的缓存策略, 根据用户习惯,而只缓存帖子的第一页(因为很少有人会翻帖子).

于此类似的思想, PHP鼓励8位一下的字符索引, 他以8为单位使用unrolled来提高效率, 这不得不说也是个很细节的,很细致的地方.

另外还有inline, register变量 … 可以看出PHP的开发者在hash的优化上也是煞费苦心

最后就是, hash的初始值设置成了5381, 相比在Apache中的times算法和Perl中的Hash算法(都采用初始hash为0), 为什么选5381呢? 具体的原因我也不知道, 但是我发现了5381的一些特性:

代码如下:

Magic Constant 5381:
1. odd number
2. prime number
3. deficient number

看了这些, 我有理由相信这个初始值的选定能提供更好的分类.

(0)

相关推荐

  • php-perl哈希算法实现(times33哈希算法)

    复制代码 代码如下: APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key,                                                      apr_ssize_t *klen){    unsigned int hash = 0;    const unsigned char *key = (const unsigned char *)char_key;  

  • PHP Hash算法:Times33算法代码实例

    最近看书,里面提到了一些Hash算法.比较有印象的是Times33,当时理解不是很透测,今天写了段程序来验证了一下. 先上代码: 复制代码 代码如下: <?php /**  * CRC32 Hash function  * @param $str  * @return int  */ function hash32($str) {     return crc32($str) >> 16 & 0x7FFFFFFF; } /**  * Times33 Hash function  

  • PHP实现的各类hash算法长度及性能测试实例

    本文实例讲述了PHP实现的各类hash算法长度及性能测试.分享给大家供大家参考,具体如下: Hash结果如下 <?php $data = "hello world"; foreach (hash_algos() as $v) { $r = hash($v, $data, false); printf("%-12s %3d %s\n", $v, strlen($r), $r); } ?> 运行结果: md2 32 d9cce882ee690a5c1ce70

  • 理解php Hash函数,增强密码安全

    1.声明 密码学是一个复杂的话题,我也不是这方面的专家.许多高校和研究机构在这方面都有长期的研究.在这篇文章里,我希望尽量使用简单易懂的方式向你展示一种安全存储Web程序密码的方法. 2."Hash"是做什么的? "Hash将一段数据(小数据或大数据)转换成一段相对短小的数据,如字符串或整数." 这是依靠单向hash函数来完成的.所谓单向是指很难(或者是实际上不可能)将其反转回来.一个常见的hash函数的例子是md5(),它流行于各种计算机语言和系统. 复制代码 代

  • PHP的password_hash()使用实例

    一.前言PHP5.5提供了许多新特性及Api函数,其中之一就是Password Hashing API(创建和校验哈希密码).它包含4个函数:password_get_info().password_hash().password_needs_rehash().password_verify().在PHP5.5之前,我们对于密码的加密可能更多的是采用md5或sha1之类的加密方式(没人像CSDN那样存明文吧..),如:echo md5("123456"); //输出: e10adc39

  • PHP 5.5 创建和验证哈希最简单的方法详解

    我们首先讨论password_hash()函数.这将用作创建一个新的密码的哈希值.它包含三个参数:密码.哈希算法.选项.前两项为必须的.你可以根据下面的例子来使用这个函数: 复制代码 代码如下: $password = 'foo';$hash = password_hash($password,PASSWORD_BCRYPT);//$2y$10$uOegXJ09qznQsKvPfxr61uWjpJBxVDH2KGJQVnodzjnglhs2WTwHu 你将注意到我们并没有给这个哈希加任何选项.现

  • 一致性哈希算法以及其PHP实现详细解析

    在做服务器负载均衡时候可供选择的负载均衡的算法有很多,包括:  轮循算法(Round Robin).哈希算法(HASH).最少连接算法(Least Connection).响应速度算法(Response Time).加权法(Weighted )等.其中哈希算法是最为常用的算法. 典型的应用场景是: 有N台服务器提供缓存服务,需要对服务器进行负载均衡,将请求平均分发到每台服务器上,每台机器负责1/N的服务. 常用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,按

  • PHP中用hash实现的数组

    PHP中使用最多的非Array莫属了,那Array是如何实现的?在PHP内部Array通过一个hashtable来实现,其中使用链接法解决hash冲突的问题,这样最坏情况下,查找Array元素的复杂度为O(N),最好则为1. 而其计算字符串hash值的方法如下,将源码摘出来以供查备: 复制代码 代码如下: static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength) { register ulong h

  • PHP随机生成唯一HASH值自定义函数

    网上有很多种方法获取随机唯一的HASH值,但是大同小异: 1.先获取随机的唯一字符串 2.进行MD5或者sha1算HASH值 一个项目要用到hash值,就去网上找了找,却发现PHP有一个函数能直接生成唯一字符串--uniqid(),通过使用这个函数,再加上自己生成的随机数(防止被破解),更具有唯一性且不易被猜解.主要考虑问题如下: 1.随机的效率与随机性:rand和mt_rand函数的选择,首选mt_rand,效率高,随机性好: 2.随机次数:选择5次,本来unniqid就是唯一的,加上随机的可

  • PHP中对各种加密算法、Hash算法的速度测试对比代码

    PHP 的Hash算法是比较常用的,现在的MD5有时候不太安全,就得用到Hash_algos()中的其它算法,下面进行了一个性能的比较. php代码: define('testtime', 50000); $algos = hash_algos(); foreach($algos as $algo) { $st = microtime(); for($i = 0; $i < testtime; $i++) { hash($algo, microtime().$i); } $et = microt

  • php 分库分表hash算法

    复制代码 代码如下: //分库分表算法 function calc_hash_db($u, $s = 4) { $h = sprintf("%u", crc32($u)); $h1 = intval(fmod($h, $s)); return $h1; } for($i=1;$i<100;$i++) { echo calc_hash_db($i); echo "<br>"; } function calc_hash_tbl($u, $n = 256

随机推荐