PHP Conference Japan 2024

spl_object_hash

(PHP 5 >= 5.2.0, PHP 7, PHP 8)

spl_object_hash 傳回給定物件的雜湊 ID

說明

spl_object_hash(object $object): string

此函式會傳回物件的唯一識別符。此 ID 可用作儲存物件的雜湊鍵,或用於識別物件,只要該物件未被銷毀。一旦物件被銷毀,其雜湊值可能會被其他物件重複使用。此行為類似於 spl_object_id()

參數

object

任何物件。

傳回值

一個字串,對於每個目前存在的物件都是唯一的,並且對於每個物件都是相同的。

範例

範例 1 spl_object_hash() 範例

<?php
$id
= spl_object_hash($object);
$storage[$id] = $object;
?>

注意事項

注意:

當物件被銷毀時,其雜湊值可能會被其他物件重複使用。

注意:

物件雜湊值應使用 ===!== 進行身分比較,因為傳回的雜湊值可能是數值字串。例如: 0000000000000e600000000000000000

參見

新增註解

使用者貢獻的註解 11 則註解

planetbeing
17 年前
請注意,該函式不會雜湊物件的內容(屬性),僅會雜湊其內部句柄和處理程序表指標。這足以保證任何兩個同時存在於記憶體中的物件將具有不同的雜湊值。無法保證在不同時存在於記憶體中的物件之間的唯一性,例如

var_dump(spl_object_hash(new stdClass()), spl_object_hash(new stdClass()));

單獨執行此操作通常會產生相同的雜湊值,因為 PHP 會在建立第二個 stdClass 後,重複使用第一個 stdClass 在被解除參考和銷毀後的內部句柄。
mjs at beebo dot org
11 年前
請注意,給定兩個不同的物件,spl_object_hash() 可能會傳回看起來非常相似的值,事實上,最高位數 *和* 最低位數都可能相同!例如 "000000003cc56d770000000007fa48c5" 和 "000000003cc56d0d0000000007fa48c5"。

因此(特別是如果使用此函式進行偵錯),您可能希望將雜湊值傳遞到加密雜湊函式(例如 md5()),以方便視覺比較,並使其前幾個或最後幾個數字更可能唯一。

md5("000000003cc56d770000000007fa48c5") -> "619a799747d348fa1caf181a72b65d9f"

md5("000000003cc56d0d0000000007fa48c5") -> "ae964bc912281e7804fe5a88b4546cb2"
A simple developer
1 年前
在 PHP >= 8.1 中比較物件雜湊值時請注意

在 PHP 8.1 中(我認為),spl_object_hash() 的輸出已變更(請參閱 pull request https://github.com/php/php-src/pull/7010)。
這導致我們的應用程式出現奇怪的行為,因為我們將物件雜湊值儲存在陣列中,以檢查是否已處理過物件。即使目前的物件雜湊值實際上 *並未* 出現在陣列中,簡單的 in_array() 檢查也會傳回 true。

實際問題:新的雜湊值更簡單,可能是像 "0000000000000e600000000000000000" 或 "0000000000000e490000000000000000" 之類的東西,PHP 會將其解釋為數值(指數)。
in_array() 預設會進行非型別安全比較,並將命名的雜湊值解釋為 "0"。
aa dot vasilenko at gmail dot com
6 年前
請注意,自 PHP 7.2 起,有新的函式 spl_object_id() 可用,該函式會傳回 int 而不是字串。據說它效能更高。由於缺乏文件,我建議您閱讀 PR https://github.com/php/php-src/pull/2611
DimeCadmium
6 年前
對於那些認為此函式名稱不當的人,我想引導您至 https://en.wikipedia.org/wiki/Hash_function。此外,對於那些認為它名稱不當並將其與 Python 比較的人,我想引導您至 https://docs.python.org/2/library/functions.html#hash,它與此函式的作用相同。(來自 Python 的資料模型文件:"使用者定義的類別預設具有 __cmp__() 和 __hash__() 方法;... x.__hash__() 會傳回從 id(x) 衍生而來的結果。" - id(x) 會傳回物件的記憶體位址。)

您熟悉的密碼雜湊函式(如 MD5 或 SHA1)被稱為雜湊函式,因為它們具有相似的設計目標:低碰撞機率。
Hayleu Watson
7 年前
此函式名稱中提到的「雜湊」指的是稱為「雜湊表」的儲存結構,而不是任何類型的「訊息摘要」。此函式傳回的字串僅僅是 PHP 維護的所有現有物件的(雜湊)表中物件的位址。
Numety
11 個月前
正如其他人所指出的,此函式現在會傳回以零填充的 ID。
它不會產生加密雜湊值(這也不是名稱所暗示的),也不會隱藏物件的建立順序。

如果您希望在隱藏物件的建立順序的同時為物件提供唯一識別符,您可以將物件的 ID 與其他可預測的值一起進行雜湊來實現此目的

<?php

function objectHash(object $object): string
{
return
hash('sha512', $object::class . spl_object_id($object));
}

?>

以下是一個使用範例

<?php

class Person
{
function
__construct(public string $name) {}
}

$anna = new Person('Anna');
$bob = new Person('Bob');

var_export(objectHash($anna)); // '077d33c1 etc.
echo "\n";
var_export(objectHash($bob)); // 'ea3c1319 etc.

?>

您可以自由選擇其他的雜湊演算法,或是將其他數值與 ID 一起雜湊,以更符合您的環境需求。
Hayley Watson
1 年前
這個函式比 spl_object_id 早一點出現。它的輸出比較複雜,但實際上提供的資訊並不比新的函式多。它過去更複雜(但資訊量並未增加),但現在它僅僅是將物件的 ID 號碼寫成十六進位,並加上大量的填充以維持舊格式。spl_object_id 則只是將 ID 號碼作為一個純粹的整數提供。

您最好使用 spl_object_id,如果您已經在使用 spl_object_hash,則應該考慮遷移;這個函式有可能在未來被棄用並隨後移除。
jasonlester at nope dot com
11 個月前
obj->handle 是一個從 0 開始的無號長整數,每次建立物件時會遞增 1,它不是真正的指標,例如由 malloc() 或類似函數建立的指標。

/* {{{ 傳回給定物件的整數物件控制代碼 */
PHP_FUNCTION(spl_object_id)
{
zend_object *obj;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJ(obj)
ZEND_PARSE_PARAMETERS_END();

RETURN_LONG((zend_long)obj->handle);
}
/* }}} */

PHPAPI zend_string *php_spl_object_hash(zend_object *obj) /* {{{*/
{
return strpprintf(32, "%016zx0000000000000000", (intptr_t)obj->handle);
}
/* }}} */
Hayley Watson
7 年前
這個函式中提到的「雜湊」是指「雜湊表」這種儲存結構的意義,而不是「訊息摘要」的意義。
Ulrich Eckhardt
7 年前
將這個稱為雜湊是非常誤導的

1. 這個函式提供一個物件識別碼(ID),在物件的整個生命週期中唯一識別該物件。這類似於 C 語言中物件的位址或 Python 中的 id() 函式。我相信其他語言也有類似的結構。
2. 這不是雜湊,而且與雜湊無關。雜湊會取得資料並以演算法將資料縮減為某種純量值。唯一的保證是兩個相同的輸入會提供相同的輸出,但不能保證兩個不同的輸入會提供不同的輸出(提示:雜湊碰撞)。然而,spl_object_hash() 保證非相同的物件會有不同的輸出。
3. 如同已經有人提過的,這個函式不會查看物件的內容。如果您考慮相等性和識別性之間的差異,它只允許確定識別性。如果您序列化並反序列化一個物件,它將不會與先前的自己相同,但它們會相等,這只是一個例子。如果您想要在回應快取中使用一個鍵,在請求上使用這個函式不僅無用,因為相等的請求會有不同的 ID,甚至可能有害,因為當請求物件被垃圾回收時,它的 ID 可能會被重複使用。
To Top