PHP setcookie() 設置的 Cookie 默認需要下一次 HTTP 請求才能在 $_COOKIE 中讀取,導致「設置後當前頁無法立即使用」的體驗問題。本文提供一個封裝函數,實現 Cookie 設置與即時讀取的同步。
<?php
/**
* 設置 Cookie 並即時生效
* @param string $name Cookie 名稱
* @param mixed $value 值(支持數組)
* @param int $expire 過期時間戳,默認 1 天
*/
public final function setCookie($name, $value, $expire = null) {
// 值為空直接返回
if (empty($value)) return;
// 默認過期時間:1 天
if (empty($expire)) $expire = time() + 86400;
// 關鍵:手動寫入 $_COOKIE 超全局變量,當前請求即可讀取
$_COOKIE[$name] = $value;
// 發送 Set-Cookie 頭給瀏覽器
if (is_array($value)) {
foreach ($value as $k => $v) {
if (empty($v)) continue;
setcookie($name . "[$k]", $v, $expire);
}
} else {
setcookie($name, $value, $expire);
}
}
| 階段 | 標準 setcookie() | 本方案 |
|---|---|---|
| 發送響應頭 | Set-Cookie: name=value | Set-Cookie: name=value |
| 當前請求 $_COOKIE | 不可用(下次請求才有) | 手動注入 $_COOKIE[$name] = $value |
| 下次請求 $_COOKIE | 可用 | 可用(瀏覽器自動攜帶) |
<?php
require 'CookieHelper.php';
$cookie = new CookieHelper();
// 設置單值
$cookie->setCookie('user_id', 10086);
echo $_COOKIE['user_id']; // 立即輸出 10086
// 設置數組
$cookie->setCookie('preferences', ['theme' => 'dark', 'lang' => 'zh-CN']);
print_r($_COOKIE['preferences']); // 立即輸出 Array ( [theme] => dark [lang] => zh-CN )
<?php
class CookieManager {
private $defaultExpire = 86400;
private $domain = '';
private $path = '/';
private $secure = false;
private $httpOnly = true;
private $sameSite = 'Lax';
public function __construct(array $config = []) {
foreach ($config as $key => $val) {
if (property_exists($this, $key)) $this->$key = $val;
}
}
public function set($name, $value, $expire = null) {
if (empty($value)) return $this->delete($name);
$expire = $expire ?? time() + $this->defaultExpire;
$_COOKIE[$name] = $value;
setcookie($name, $value, $expire, $this->path, $this->domain, $this->secure, $this->httpOnly);
return $this;
}
public function setArray($name, array $value, $expire = null) {
foreach ($value as $k => $v) {
$this->set("{$name}[{$k}]", $v, $expire);
}
return $this;
}
public function get($name, $default = null) {
return $_COOKIE[$name] ?? $default;
}
public function delete($name) {
unset($_COOKIE[$name]);
setcookie($name, '', time() - 3600, $this->path, $this->domain, $this->secure, $this->httpOnly);
return $this;
}
public function has($name) {
return isset($_COOKIE[$name]);
}
public function clear() {
foreach (array_keys($_COOKIE) as $name) {
$this->delete($name);
}
}
}
<?php
// login.php
if ($user = verifyCredentials($username, $password)) {
$cookie = new CookieManager(['httpOnly' => true, 'secure' => true]);
$cookie->set('user_id', $user['id'])
->set('token', generateToken($user['id']))
->setArray('profile', ['name' => $user['name'], 'avatar' => $user['avatar']]);
// 當前頁面即可讀取
header('Location: /dashboard');
exit;
}
<?php
// add_to_cart.php
$cart = json_decode($_COOKIE['cart'] ?? '[]', true);
$cart[$productId] = ($cart[$productId] ?? 0) + 1;
$cookie = new CookieManager();
$cookie->set('cart', json_encode($cart), time() + 30*86400);
// 當前頁面導航欄即可顯示最新數量
$total = array_sum(json_decode($_COOKIE['cart'], true));
echo "購物車($total)";
結合 localStorage + storage 事件 + 定時輪詢,實現跨標籤頁 Cookie 狀態同步:
<script>
// 監聽其他標籤頁的 Cookie 變更
window.addEventListener('storage', (e) => {
if (e.key === 'sync_cookie') {
location.reload(); // 或局部更新 UI
}
});
// 設置 Cookie 時同步通知
function setCookieWithSync(name, value, days) {
document.cookie = `${name}=${value};max-age=${days*86400};path=/`;
localStorage.setItem('sync_cookie', Date.now()); // 觸發 storage 事件
}
</script>
HttpOnly、Secure(HTTPS)、SameSite=Lax/Stricturlencode()/urldecode() 或 JSON 序列化通過手動寫入 $_COOKIE 超全局數組,配合標準 setcookie() 發送響應頭,即可實現 PHP Cookie 的「設置即讀取」。封裝為可復用類後,能優雅處理數組存儲、安全屬性、跨域同步等複雜場景,是 PHP 開發者工具箱中的實用小技巧。