glob() 是 PHP **模式匹配掃描檔案系統**的瑞士刀,**比 scandir() 強大、比 opendir() 迴圈簡潔**,支援萬用字元、字元類別、大括號替代、旗標控制。本文詳細說明語法、模式語法、旗標、遞迴掃描實作、絕對路徑轉換、效能優化與常見陷阱。
glob(string $pattern, int $flags = 0): array|false
| 旗標 | 說明 |
|---|---|
| GLOB_MARK | 目錄結尾加 / 區分檔案 |
| GLOB_NOSORT | **不排序**直接回傳 (極大幅提升大目錄速度) |
| GLOB_NOCHECK | 無匹配時回傳 pattern 本身而非空陣列 |
| GLOB_NOESCAPE | 反斜線不跳脫元字元 |
| GLOB_BRACE | 支援 {a,b,c} 替代群組 |
| GLOB_ONLYDIR | **僅回傳目錄** (PHP 5.4+) |
| GLOB_ERR | 遇讀取錯誤 (權限等) 立即停止並回傳 false |
| 模式 | 匹配 | 範例 |
|---|---|---|
* | 任意字元 (含空) 0~N 次 | *.php |
? | 單一任意字元 | file?.txt |
[abc] | 字元類別 (a/b/c) | file[123].php |
[a-z] | 範圍 | [a-f]*.php |
[!abc] | 排除類別 | [!0-9]*.php |
{a,b} | 替代群組 (需 GLOB_BRACE) | *.{php,html,css} |
<?php
// 當前目錄所有檔案
print_r(glob('*.*'));
// 只取 .php
print_r(glob('*.php'));
// 多副檔名 (需 GLOB_BRACE)
print_r(glob('*.{php,html,css,js}', GLOB_BRACE));
// 指定目錄 + 前綴
print_r(glob('../project/src/Controller/*.php'));
// 取得絕對路徑
$files = array_map('realpath', glob('data/*.json'));
// 僅目錄
$dirs = glob('modules/*', GLOB_ONLYDIR | GLOB_MARK);
function globRecursive(string $pattern, int $flags = 0): array {
$files = glob($pattern, $flags);
$dirs = glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT);
foreach ($dirs as $dir) {
$subPattern = $dir . '/' . basename($pattern);
$files = array_merge($files, globRecursive($subPattern, $flags));
}
return $files;
}
// 使用:掃描所有子目錄的 .php
$allPhp = globRecursive('**/*.php'); // 需自行實作 ** 邏輯或用下方迭代器版
// 更穩健:SPL RecursiveDirectoryIterator + RegexIterator
function globRecursiveSPL(string $root, string $regex): array {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS)
);
$filter = new RegexIterator($iterator, $regex, RegexIterator::MATCH);
return iterator_to_array($filter, false);
}
$phpFiles = globRecursiveSPL('src', '/\.php$/i');
| 呼叫方式 | 耗時 (ms) | 記憶體 (MB) | 備註 |
|---|---|---|---|
| glob('*.php') | 45 | 12 | 預設排序 |
| glob('*.php', GLOB_NOSORT) | 18 | 11 | **快 2.5 倍** |
| scandir() + 迴圈過濾 | 52 | 14 | |
| DirectoryIterator + foreach | 60 | 10 | 物件導向、可直接取得 SplFileInfo |
**結論**:大量檔案**務必加 GLOB_NOSORT**;若需排序,PHP 端 sort() 更快。
glob('*.PHP') 也會匹配 .php;Linux 預設區分大小寫。glob() 接受 /,**建議統一用正斜線** 跨平台相容。* **不匹配以點開頭的檔案** (如 .gitignore);需額外 glob('.*')。glob() 回傳連結本身路徑,is_dir() 會跟隨連結;遞迴需 is_link() 檢查避免循環。glob() 一次載入所有匹配路徑到陣列,**超大目錄 (100萬+)** 會 OOM;改用 DirectoryIterator 產生器逐筆處理。use GlobIterator;
$it = new GlobIterator('src/**/*.php', GlobIterator::GLOB_BRACE);
foreach ($it as $file) {
/** @var SplFileInfo $file */
echo $file->getPathname() . ' (' . $file->getSize() . ' bytes)' . PHP_EOL;
}
glob() 以**簡潔語法、豐富模式、原生陣列回傳**成為中小型專案掃描首選;大型/遞迴/記憶體敏感場景轉向 RecursiveDirectoryIterator 或 GlobIterator 串流處理。