func_get_args() / ... 操作符PHP 支援任意數量參數,現代寫法使用 ...(PHP 5.6+):
<?php
// 現代寫法(推薦)
function sum(...$numbers): float
{
return array_sum($numbers);
}
echo sum(1, 2, 3, 4.5); // 10.5
// 經典寫法(兼容舊版)
function legacySum()
{
$args = func_get_args();
return array_sum($args);
}
// 結合類型提示(PHP 8+)
function logMessage(string $level, string ...$messages): void
{
foreach ($messages as $msg) {
error_log("[$level] $msg");
}
}
logMessage('INFO', 'User login', 'IP: 192.168.1.1');
glob() 文件模式匹配(比 scandir() 更強)<?php
// 所有 PHP 文件
$phpFiles = glob('*.php');
// 多擴展名(需 GLOB_BRACE)
$codeFiles = glob('*.{php,js,css,html}', GLOB_BRACE);
// 遞歸查找(PHP 5.5+ GLOB_BRACE 不支援遞歸,需配合 RecursiveDirectoryIterator)
$allPhp = glob('src/**/*.php', GLOB_BRACE); // 不支援 **,見下文
// 正確遞歸查找
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('src', RecursiveDirectoryIterator::SKIP_DOTS)
);
$phpFiles = new RegexIterator($iterator, '/\.php$/i');
// 獲取絕對路徑
$absPaths = array_map('realpath', glob('../images/a*.jpg'));
memory_get_usage() / memory_get_peak_usage()<?php
echo "初始內存: " . memory_get_usage() . " bytes\n"; // ~360KB
// 分配大數組
$data = [];
for ($i = 0; $i < 100000; $i++) {
$data[] = md5($i);
}
echo "峰值內存: " . memory_get_peak_usage() . " bytes\n"; // ~13MB
// 釋放一半
for ($i = 0; $i < 50000; $i++) {
unset($data[$i]);
}
echo "當前內存: " . memory_get_usage() . " bytes\n"; // ~8MB
// 實際項目中:監控內存洩漏
register_shutdown_function(function() {
$peak = memory_get_peak_usage(true); // 真實系統分配
if ($peak > 100 * 1024 * 1024) { // 100MB 閾值
error_log("Memory peak exceeded: " . ($peak / 1024 / 1024) . " MB");
}
});
getrusage()(僅 Linux/Unix)<?php
// 僅 CLI/Unix 環境可用
$data = getrusage();
// 用戶態 CPU 時間(秒)
$userTime = $data['ru_utime.tv_sec'] + $data['ru_utime.tv_usec'] / 1_000_000;
// 內核態 CPU 時間
$sysTime = $data['ru_stime.tv_sec'] + $data['ru_stime.tv_usec'] / 1_000_000;
echo "用戶態: $userTime 秒, 內核態: $sysTime 秒\n";
// 對比:睡眠 vs 計算
sleep(3); // 不佔用 CPU
$data = getrusage();
echo "睡眠後用戶態: " . ($data['ru_utime.tv_sec'] + $data['ru_utime.tv_usec']/1e6) . "\n"; // ~0
// 密集計算
for ($i = 0; $i < 10_000_000; $i++) {}
$data = getrusage();
echo "計算後用戶態: " . ($data['ru_utime.tv_sec'] + $data['ru_utime.tv_usec']/1e6) . "\n"; // ~1.4s
| 常量 | 含義 | 典型用途 |
|---|---|---|
__LINE__ | 當前行號 | 調試輸出、錯誤定位 |
__FILE__ | 當前文件完整路徑 | require_once dirname(__FILE__) . '/config.php' |
__DIR__ | 當前文件目錄(PHP 5.3+) | require __DIR__ . '/config.php' 更簡潔 |
__FUNCTION__ | 函數名 | 日誌記錄、AOP 切面 |
__CLASS__ | 類名 | 工廠模式、反射 |
__METHOD__ | 類方法名 | 精確調試定位 |
__NAMESPACE__ | 命名空間 | 動態類加載 |
function debug(mixed $msg): void
{
$bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1] ?? [];
echo "[{$bt['file'] ?? '?'}]:{$bt['line'] ?? '?'} {$bt['function'] ?? '?'} - $msg\n";
}
debug('進入訂單處理'); // [/app/Order.php:45] handle - 進入訂單處理
uniqid() vs md5()<?php
// ❌ 老舊寫法:長、無序、無語義
$id = md5(time() . mt_rand(1, 1000000)); // 32 字符
// ✅ 現代寫法:短、按時間有序、可加前綴
echo uniqid(); // 4bd67c947233e (13 字符,微秒級時間)
echo uniqid('order_'); // order_4bd67c947233e (帶前綴)
echo uniqid('', true); // 4bd67c947233e.12345678 (更多熵,含微秒小數)
echo uniqid('usr_', true); // usr_4bd67c947233e.12345678
// 極高併發/分布式:UUID v4 / ULID / Snowflake
// 使用 ramsey/uuid 或自定義 Snowflake 實現
serialize() vs json_encode()<?php
$data = ['hello', 42, [1, 'two'], 'apple'];
// PHP 原生序列化(含類型、對象)
$ser = serialize($data);
// a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";}
$restored = unserialize($ser);
// JSON(跨語言、可讀、緊湊)
$json = json_encode($data);
// ["hello",42,[1,"two"],"apple"]
$restored = json_decode($json, true); // true 返回關聯數組
// 對比
/*
| 特性 | serialize() | json_encode() |
| 類型保持 | ✅ 完整 | ⚠️ 數字/字符串/數組/對象 |
| 對象支援 | ✅ 含私有屬性 | ❌ 僅公共屬性 |
| 跨語言 | ❌ PHP 專用 | ✅ 標準格式 |
| 性能 | 較快 | 較慢 (解析開銷) |
| 安全性 | ⚠️ 反序列化風險 | ✅ 安全 |
*/
// 建議:緩存/存儲用 JSON,會話/內部傳遞用 serialize(信任數據源前提)
gzcompress() / gzencode()<?php
$text = "Lorem ipsum dolor sit amet... (800 字節長文本)";
$compressed = gzcompress($text); // zlib 壓縮
echo "原始: " . strlen($text) . " 字節\n"; // 800
echo "壓縮: " . strlen($compressed) . " 字節\n"; // ~418 (近 50%)
$original = gzuncompress($compressed); // 解壓
// gzencode() 使用 gzip 格式(含頭部),適合 HTTP 傳輸
$gzipped = gzencode($text, 9); // 級別 1-9
// 瀏覽器可直接解碼 gzip Content-Encoding
register_shutdown_function()<?php
// 問題:exit() / 致命錯誤 / 瀏覽器關閉 導致腳本中途結束,末尾代碼不執行
$start = microtime(true);
// ... 業務邏輯 ...
echo "耗時: " . (microtime(true) - $start) . " 秒"; // 可能不執行
// 解決:註冊關閉函數,無論如何退出都會執行
$start = microtime(true);
register_shutdown_function(function() use ($start) {
echo "總耗時: " . (microtime(true) - $start) . " 秒\n";
// 可在此記錄日誌、發送監控指標、釋放鎖等
});
// 模擬中途退出
if (rand(0, 1)) exit('隨機退出');
// 即使 exit,關閉函數仍會執行
<?php
class PerformanceMiddleware
{
public function handle(callable $next): mixed
{
$startTime = microtime(true);
$startMem = memory_get_usage();
$startCpu = getrusage();
register_shutdown_function([$this, 'logMetrics'], $startTime, $startMem, $startCpu);
return $next();
}
public function logMetrics(float $startTime, int $startMem, array $startCpu): void
{
$time = microtime(true) - $startTime;
$mem = memory_get_peak_usage(true) - $startMem;
$cpu = getrusage();
$userCpu = ($cpu['ru_utime.tv_sec'] + $cpu['ru_utime.tv_usec']/1e6) -
($startCpu['ru_utime.tv_sec'] + $startCpu['ru_utime.tv_usec']/1e6);
error_log(json_encode([
'time_ms' => round($time * 1000, 2),
'memory_kb' => round($mem / 1024, 2),
'cpu_user_sec' => round($userCpu, 4),
'url' => $_SERVER['REQUEST_URI'] ?? 'cli',
]));
}
}