首先原題是這樣子的:
寫一個函數,計算出兩個文件的相對路徑,如 $a = '/a/b/c/d/d.php',$b = '/a/b/1/2/c.php'
計算出的$b相對於$a的相對路徑應該是:../../c/d
那麼對於網上給出的答案,看了看貌似只能針對題目中給出的那個路徑來計算,如果路徑一變化,類似下面這樣,那麼那些程序好像沒用了,當然有些是有用,但是還是報一些警告出來。。。。。
例如:
$a = '/a/b/c/d/e/f/g/h/e.php'
$b = '/a/b/1/2/c.php'
再例如:
$a = '/a/e.php'
$b = '/a/b/c/d/1/2/c.php'
再例如:
$a = '/a/b/c/d/d.php'
$b = '/a/b/c/d/c.php'
所以這個情況挺多的,不能僅僅看當下的需求!
首先還是說下這個題目的意圖吧,它的要求是求$b相對於$a的一個相對路徑,也就是說是個什麼意思呢。
就是從$b所給定的那個文件通過相對路徑的方式表示怎麼樣可以找到$a所對應的那個文件。就那題目給出的那個路徑來解釋,就是我們怎麼$b到達$a呢,那首先從$b出發需要“../”上一級目錄然後再“../”上一級目錄來到了“/a/b”這個目錄下,然後接着再從這個目錄下出發,連接上“/c/d”然後就來到了$a所對應的目錄。
也就是說,這個題目的主要任務是找到從$b到$a需要“上幾級”才能到達和$a具有相同目錄的地方,然後接着連接上$a接下來的那部分,那麼我們就得到了答案,所以題目的關鍵是找到底需要“上幾級”!
廢話不多說,直接看代碼:
/**
* 計算$b相對於$a的相對路徑
* @param string $a
* @param string $b
* @return string
*/
function getRelativePath($a, $b) {
$relativePath = "";
$pathA = explode('/', dirname($a));
$pathB = explode('/', dirname($b));
$n = 0;
$len = count($pathB) > count($pathA) ? count($pathA) : count($pathB);
do {
if ( $n >= $len || $pathA[$n] != $pathB[$n] ) {
break;
}
} while (++$n);
$relativePath .= str_repeat('../', count($pathB) - $n);
$relativePath .= implode('/', array_splice($pathA, $n));
return $relativePath;
}
$res = getRelativePath($a, $b);
var_dump($res);
經過測試呢,上面列舉的情況都滿足。
那這段程序需要解釋的就是:
$len爲什麼需要求出$a和$b中路徑最少的一個?
那是因爲下面我們通過do{}while();循環來從0即起始路徑開始向下一直對比$a和$b的路徑,希望找到是從哪個路徑開始導致$a和$b不一樣了,也就是從找到了$a和$b路徑總共相同的路徑數是幾個了。那在尋找的過程中,如果出現$a和$b的路徑一直不相等那麼$n會一直增加導致陷入死循環,所以還需要另外一個條件,就是我們需要讓$n的最大值不能超過$a和$b中路徑最短的一個,爲什麼呢?因爲$n一旦大於了$len那說明有一個路徑已經結束了,那直到結束也沒有找到$a和$b不一樣的那個部分,那說明其中最短路徑的長度正好是他們路徑相同的數目。(多數其它程序就範了這個錯誤),也就不需要繼續找了,因爲我們已經找到了。
找到了相同路徑的個數之後,首先需要計算的是:從$b到$a到底需要幾個“../”,那麼計算方法就是用“count($pathB) - $n”,爲什麼呢?因爲$n表示路徑相同的數目,而“ count($pathB)”表示$b的路徑數,那麼相互一減就得到了不同的路徑數目也就是需要的幾個“../”,那麼減完之後的結果一定是大於等0的值,所以沒問題!
找到了從$b到$a需要幾個“../”之後的任務就是將這幾個“../”和$a中不同的路徑部分拼接一下就可以了,也就是代碼:$relativePath .= implode('/', array_splice($pathA, $n));
到此,結束!