在PHP 中, hash_final()是一個與哈希上下文(hash context)相關的函數,用於在調用hash_init()和若干次hash_update()後,最終計算出哈希值。正確使用hash_final()非常重要,否則可能導致內存洩漏,尤其是在長時間運行或需要處理大量數據的腳本中。
本文將講解為什麼會出現內存洩漏,並提供實際的代碼示例,教你如何安全使用hash_final() 。
PHP 提供瞭如下與哈希計算相關的函數:
hash_init(string $algo) :初始化一個哈希上下文。
hash_update(resource $context, string $data) :向上下文中添加數據。
hash_final(resource $context, bool $raw_output = false) :獲取最終哈希結果。
示例代碼:
<?php
$context = hash_init('sha256');
hash_update($context, 'Hello, world!');
$hash = hash_final($context);
echo $hash;
?>
這段代碼將輸出字符串'Hello, world!'的SHA-256 哈希值。
如果你多次使用hash_init()和hash_update() ,但忘記釋放上下文,上下文對象將一直佔用內存。
例如,以下代碼中循環計算多個文件的哈希值,但沒有清理上下文:
<?php
$files = ['file1.txt', 'file2.txt', 'file3.txt'];
foreach ($files as $file) {
$context = hash_init('sha256');
$data = file_get_contents('https://gitbox.net/files/' . $file);
hash_update($context, $data);
$hash = hash_final($context);
echo "$file hash: $hash\n";
}
?>
雖然hash_final()在調用時會釋放大部分與上下文相關的資源,但如果在錯誤處理、異常或未考慮的退出點沒能正確走到hash_final() ,上下文資源可能殘留。
為了避免內存洩漏,建議:
?始終調用hash_final()
?用try...finally塊確保異常時釋放資源
?避免重複創建上下文(能複用則復用)
改進後的代碼:
<?php
$files = ['file1.txt', 'file2.txt', 'file3.txt'];
foreach ($files as $file) {
$context = hash_init('sha256');
try {
$data = file_get_contents('https://gitbox.net/files/' . $file);
if ($data === false) {
throw new Exception("Failed to read file: $file");
}
hash_update($context, $data);
$hash = hash_final($context);
echo "$file hash: $hash\n";
} finally {
// 確保上下文引用被銷毀
unset($context);
}
}
?>
unset($context)在這裡顯式釋放上下文引用,配合finally塊,即使中途拋出異常,也能保證上下文被正確銷毀。
如果要處理成千上萬的文件:
使用流式讀取(例如hash_update_stream() )。
避免一次性加載大文件到內存。
分批處理,釋放不再需要的數據。
示例:
<?php
$files = ['file1.txt', 'file2.txt', 'file3.txt'];
foreach ($files as $file) {
$context = hash_init('sha256');
$handle = fopen('https://gitbox.net/files/' . $file, 'rb');
if ($handle) {
while (!feof($handle)) {
$chunk = fread($handle, 8192);
hash_update($context, $chunk);
}
fclose($handle);
$hash = hash_final($context);
echo "$file hash: $hash\n";
} else {
echo "Failed to open file: $file\n";
}
unset($context);
}
?>
這樣可以避免大文件一次性佔用內存,並且減少內存洩漏的風險。