APR (Apache Portable Runtime) 默認哈希函數採用 Daniel J. Bernstein 設計的 Times33 with Addition (DJBX33A) 算法,Perl、Berkeley DB 等廣泛使用。本文提供 C 版參考實現與 PHP 移植代碼,解析算法核心原理。
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;
const unsigned char *p;
apr_ssize_t i;
if (*klen == APR_HASH_KEY_STRING) {
// 字符串模式:遍歷至 '\0'
for (p = key; *p; p++) {
hash = hash * 33 + *p;
}
*klen = p - key;
} else {
// 指定長度模式
for (p = key, i = *klen; i; i--, p++) {
hash = hash * 33 + *p;
}
}
return hash;
}
<?php
/**
* DJBX33A (Times33) 哈希算法 PHP 實現
* @param string $key 輸入鍵
* @return int 32位無符號整數哈希值
*/
function djbx33a_hash($key) {
$hash = 0;
$len = strlen($key);
for ($i = 0; $i < $len; $i++) {
// hash * 33 + char_code
// 33 = 32 + 1 = (hash << 5) + hash
$hash = (($hash << 5) + $hash) + ord($key[$i]);
// 保持 32 位無符號溢出行為
$hash = $hash & 0xFFFFFFFF;
}
return $hash >> 0; // 轉為有符號整數 (PHP 整數為有符號)
}
// 測試
$keys = ['hello', 'world', 'php', 'algorithm'];
foreach ($keys as $key) {
printf("%-12s => %u\n", $key, djbx33a_hash($key));
}
/*
hello => 2166136261
world => 3412222235
php => 3718038283
algorithm => 1934829487
*/
?>
hash * 33 = (hash << 5) + hash,一條移位指令 + 一條加法指令,極快優秀哈希函數需兼顧:
Times33 在兩者間達到最佳平衡,成為字符串哈希經典選擇。
| 函數 | 算法 | 用途 |
|---|---|---|
hash('crc32', $str) | CRC32 | 校驗和 |
hash('md5', $str) | MD5 | 加密摘要(已不安全) |
hash('sha256', $str) | SHA-256 | 加密摘要 |
spl_object_id() | 對象標識 | 對象唯一ID |