獲取文件擴展名是高頻需求,PHP 提供多種路徑。本文對比 4 種主流寫法的優劣、邊界行為(無後綴、多點、隱藏文件、路徑含查詢參數),推薦最穩健的 pathinfo() 方案。
| 方法 | 代碼 | 優點 | 缺點/邊界問題 |
|---|---|---|---|
| pathinfo() 推薦 | pathinfo($file, PATHINFO_EXTENSION) | 內建、處理路徑分隔符、無後綴返回空串、不受查詢參數影響 | 極長路徑略慢(可忽略) |
| SplFileInfo | (new SplFileInfo($file))->getExtension() | 物件導向、可鏈式調用其他資訊 | 實例化開銷稍大 |
| strrchr + substr | substr(strrchr($file, '.'), 1) | 單行、無函數調用開銷 | 目錄含點會誤判、查詢參數污染、無後綴返回整串 |
| explode 取末尾 | end(explode('.', $file)) | 簡單直觀 | 同 strrchr,且 explode 全部分割記憶體佔用大 |
<?php
$tests = [
'image.jpg' => 'jpg',
'/var/www/image.png' => 'png',
'archive.tar.gz' => 'gz', // 雙後綴取最後
'.htaccess' => '', // 隱藏文件無後綴
'README' => '', // 無點
'file.name.with.dots' => 'dots', // 多點取最後
'script.php?ver=1.2' => 'php?ver=1.2', // 查詢參數污染(除 pathinfo 外)
'path/to/.hidden/file' => '', // 目錄含隱藏文件
];
foreach ($tests as $file => $expected) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
echo "$file → [$ext] " . ($ext === $expected ? '✅' : '❌') . PHP_EOL;
}
?>
<?php
/**
* 穩健獲取文件擴展名(小寫)
* @param string $path 文件路徑或 URL
* @return string 小寫擴展名,無則返回空串
*/
function get_file_extension(string $path): string {
// 1. 移除 URL 查詢字串與片段
$path = parse_url($path, PHP_URL_PATH) ?? $path;
// 2. 獲取擴展名
$ext = pathinfo($path, PATHINFO_EXTENSION);
// 3. 統一小寫
return strtolower($ext);
}
// 測試
var_dump(get_file_extension('IMG.JPG')); // "jpg"
var_dump(get_file_extension('/cdn/file.PNG?v=2')); // "png"
var_dump(get_file_extension('.env')); // ""
var_dump(get_file_extension('data')); // ""
?>
<?php
$file = '/var/www/html/assets/images/photo.jpg';
$iter = 1_000_000;
$t = microtime(true);
for ($i=0;$i<$iter;$i++) pathinfo($file, PATHINFO_EXTENSION);
echo "pathinfo: " . (microtime(true)-$t) . "s\n"; // ~0.18s
$t = microtime(true);
for ($i=0;$i<$iter;$i++) (new SplFileInfo($file))->getExtension();
echo "SplFileInfo: " . (microtime(true)-$t) . "s\n"; // ~0.45s
$t = microtime(true);
for ($i=0;$i<$iter;$i++) substr(strrchr($file, '.'), 1);
echo "strrchr: " . (microtime(true)-$t) . "s\n"; // ~0.12s (但邊界不可靠)
?>
結論:
pathinfo()性能與簡單字串操作同量級,且正確性最高,**首選**。高頻熱點路徑可緩存結果或用SplFileInfo復用實例。