在建構檔案連結、產生相對匯入路徑時,常需要根據兩個絕對路徑計算相對路徑。本文實作一個 getRelativePath() 函數,支援任意深度目錄結構,並處理同名子目錄的邊界情況。
<?php
/**
* 取得 $b 相對於 $a 的相對路徑
*
* @param string $a 基準路徑(絕對路徑)
* @param string $b 目標路徑(絕對路徑)
* @return string 相對路徑(以 ../ 開頭)
*/
function getRelativePath(string $a, string $b): string {
// 1. 分割路徑片段,過濾空值
$pathA = array_values(array_filter(explode('/', $a), 'strlen'));
$pathB = array_values(array_filter(explode('/', $b), 'strlen'));
// 2. 找出共同前綴長度
$commonLen = 0;
$minLen = min(count($pathA), count($pathB));
for ($i = 0; $i < $minLen; $i++) {
if ($pathA[$i] === $pathB[$i]) {
$commonLen++;
} else {
break;
}
}
// 3. 建構相對路徑:先回溯到共同祖先,再前進到目標
$upSteps = count($pathA) - $commonLen;
$downSegments = array_slice($pathB, $commonLen);
$relative = str_repeat('../', $upSteps) . implode('/', $downSegments);
// 若目標是目錄(原路徑以 / 結尾),補上尾隨斜線
if (substr($b, -1) === '/') {
$relative .= '/';
}
return $relative;
}
// 測試範例
$a = '/a/c/d/e.php';
$b = '/a/c.php';
echo getRelativePath($a, $b); // 輸出:../../c.php
// 更多測試
var_dump([
getRelativePath('/a/b/c/d/e.php', '/a/b/12/34/c.php'), // ../../../12/34/c.php
getRelativePath('/var/www/html/project', '/var/www/html/project/public'), // public
getRelativePath('/home/user/docs', '/home/user/photos'), // ../photos
]);
?>
../。./。/a 與 /b 共同前綴為空,回溯層數為 1(../)。<?php
use Symfony\Component\String\ByteString;
$relative = (new ByteString($b))->getRelativePath($a);
// 需 composer require symfony/string
?>
getRelativePath() 以清晰演算法解決相對路徑計算,無外部依賴,易於整合。希望本文對您的 PHP 程式設計有所幫助。