無論是已知參數名直接取值,或是未知情況下解析完整 URL,PHP 提供多種內建方式。本文詳細對比 $_SERVER、pathinfo()、parse_url()、basename() 四大方法的輸出差異、適用場景與最佳實踐。
$url = 'https://localhost/index.php?name=tank&sex=1#top';
<?php
// 僅適用於「當前 HTTP 請求」的 URL 解析
echo $_SERVER['QUERY_STRING']; // name=tank&sex=1 (純查詢字串)
echo $_SERVER['REQUEST_URI']; // /index.php?name=tank&sex=1#top (含路徑、查詢、錨點)
echo $_SERVER['PHP_SELF']; // /index.php (腳本路徑)
// 注意:$_SERVER 只能解析「當前請求」,無法解析任意字串 URL
<?php
$info = pathinfo($url);
print_r($info);
/*
Array
(
[dirname] => https://localhost // 目錄路徑
[basename] => index.php // 完整檔名
[extension] => php // 副檔名
[filename] => index // 不含副檔名的檔名
)
*/
// ⚠️ 注意:pathinfo() 主要針對「檔案路徑」,對 URL 的 query/fragment 解析不支援
<?php
$parts = parse_url($url);
print_r($parts);
/*
Array
(
[scheme] => http // 協定
[host] => localhost // 主機
[path] => /index.php // 路徑
[query] => name=tank&sex=1 // 查詢字串 (無 ?)
[fragment] => top // 錨點 (無 #)
)
*/
// 進階:解析 query 字串為陣列
parse_str($parts['query'], $queryParams);
print_r($queryParams);
/*
Array
(
[name] => tank
[sex] => 1
)
*/
<?php
echo basename($url); // index.php?name=tank&sex=1#top
// 等同於 pathinfo($url, PATHINFO_BASENAME)
// 注意:basename() 不解析,只取「最後一段」包含 query/fragment
<?php
preg_match_all('/(\w+=\w+)(#\w+)?/i', $url, $matches);
print_r($matches);
/*
Array
(
[0] => Array ( [0] => name=tank, [1] => sex=1#top )
[1] => Array ( [0] => name=tank, [1] => sex=1 )
[2] => Array ( [0] => , [1] => #top )
)
*/
| 方法 | 適用對象 | 解析能力 | 效能 | 推薦場景 |
|---|---|---|---|---|
$_SERVER | 當前請求 | 查詢字串、完整 URI | 極快 (已解析) | 取得當前請求參數 |
pathinfo() | 檔案路徑/URL | 目錄、檔名、副檔名 | 快 | 解析路徑結構、取副檔名 |
parse_url() | 任意 URL 字串 | 完整結構 (scheme/host/path/query/fragment/port/user/pass) | 快 | 通用 URL 解析首選 |
basename() | 路徑/URL | 最後一段 (含 query/fragment) | 極快 | 快速取得「檔名+參數」 |
| 正則 | 任意字串 | 完全自定義 | 慢 | 特殊格式、舊版相容 |
<?php
/**
* 完整 URL 解析工具函數
* @param string $url
* @return array [scheme, host, port, path, query(array), fragment]
*/
function parseUrlComplete(string $url): array {
$parts = parse_url($url);
$result = [
'scheme' => $parts['scheme'] ?? '',
'host' => $parts['host'] ?? '',
'port' => $parts['port'] ?? (($parts['scheme'] ?? '') === 'https' ? 443 : 80),
'path' => $parts['path'] ?? '/',
'query' => [],
'fragment' => $parts['fragment'] ?? '',
];
if (!empty($parts['query'])) {
parse_str($parts['query'], $result['query']);
}
if (!empty($parts['user'])) {
$result['user'] = $parts['user'];
$result['pass'] = $parts['pass'] ?? '';
}
return $result;
}
// 使用
$parsed = parseUrlComplete('https://user:pass@api.example.com:8443/v1/users?name=John&age=25#section2');
/*
[
'scheme' => 'https',
'host' => 'api.example.com',
'port' => 8443,
'path' => '/v1/users',
'query' => ['name' => 'John', 'age' => '25'],
'fragment' => 'section2',
'user' => 'user',
'pass' => 'pass',
]
*/
parse_url() 不支援相對路徑 (需有 scheme),如 parse_url('/path?query') 會失敗parse_str() 會覆蓋同名參數 (最後一個生效),多值參數需用 parse_str($str, $arr) 陣列模式$_SERVER['QUERY_STRING'] 未經 URL 解碼,需搭配 urldecode() 或 parse_str()basename() 在 Windows 路徑分隔符 \ 下行為不同parse_url() + parse_str()**$_GET、$_POST、$_REQUEST