本文最後結論:PHP的realpath函數不支持phar文件。通過網友指出,是我腦殼發熱,自覺得是的 let_it_work函數,覺得生效,其實裏面存在很是致命的邏輯錯誤,我記住教訓了。php
爲了留下的記錄,文章內容一字不改,只在 let_it_work 函數那裏註釋了一下。php7
這事情教育我,仍是得要單元測試,這種想固然錯誤太明顯了。函數
實在是忍不住要吐槽一下,從7.0.0到7.0.4的時候,我一直在看這個bug,並且也發去php issues了,已經說修復了,可是顯然並無修復。後來忙,就沒管這個問題了,但是到今天,都7.0.14了,7.1.0都發布了,仍是沒修復啊!單元測試
假定我有一個phar包,包內結構以下:測試
$paths = [ 'phar://phar_test.phar/hello', 'phar://phar_test.phar/hello/a.php', ];
上述的這個路徑,是存在的。spa
執行測試:code
foreach ($paths as $path) { var_dump(file_exists($path)); // return true var_dump(realpath($path)); // return false }
輸出結果以下:接口
若是用file_exists檢查,那麼他是返回true的,文件是存在的。內存
用realpath檢查,他返回了false,就是返回真實路徑的時候,他沒法返回相對應的真實路徑。get
因此,通常到這裏,會讓咱們得出一個想固然的結論:realpath顯然不支持phar包。
問題並無結束,顯然realpath是支持phar的,此次咱們加一個函數:
function let_it_work(string $path) { $realPath = realpath($path); if ($realPath !== false) { $path = $realPath; } // 這裏我想固然了 // 應該改成 return false return $path; }
這個函數其實沒啥特別,可是他卻能讓咱們獲得想要的結果。
執行下列測試程序:
foreach ($paths as $path) { var_dump(file_exists($path)); // return true var_dump(realpath($path)); // return false var_dump(let_it_work($path)); // 輸出 "phar://phar_test.phar/hello" 和 "phar://phar_test.phar/hello/a.php" }
咱們會獲得以下的結果:
顯然realpath函數仍是生效了。否則是不會獲得真實路徑的。
那麼是否是給realpath包一層函數,就能獲得咱們想要的結果呢?那我再加一個函數:
function realpath2(string $path) { return realpath($path); }
執行如下測試:
foreach ($paths as $path) { var_dump(file_exists($path)); // return true var_dump(realpath($path)); // return false var_dump(let_it_work($path)); // 輸出 "phar://phar_test.phar/hello" 和 "phar://phar_test.phar/hello/a.php" var_dump(realpath2($path)); // 和realpath返回結果同樣 }
獲得以下的結果:
顯然包一層函數是不能解決問題的。
這個問題,並不止於realpath函數,全部獲取realpath的函數,都存在這個問題。好比目錄迭代器 DirectoryIterator,咱們再寫一個函數:
function entry(DirectoryIterator $dir) { foreach ($dir as $item) { $path = $item->getPathname(); var_dump(file_exists($path)); // true var_dump($item->getRealPath()); // false var_dump(let_it_work($path)); // 這裏返回的結果,是正確的 } } entry(new DirectoryIterator('phar://phar_test.phar'));
這個測試很簡單,就是傳入一個目錄迭代器,而後遍歷目錄下的內容,而後調用 getRealPath 方法以進行測試。
執行結果以下:
不出所料,getRealPath返回仍是返回無效的結果。
其實這個問題看上去,並非一個很嚴重的問題,並且也有解決方案了,因此也沒什麼可抱怨的。
可是冷靜分析一下let_it_work的函數,問題的關鍵在於:
if ($realPath !== false) { $path = $realPath; }
$path變量是函數的參數傳入的,可是到這裏,我把他和false作了一次比較,而後又把他寫入了另外一個變量的結果,這樣就改變告終果。這裏實際上是一個很嚴重的問題,就是變量的內存地址問題。也就是說,經過一些操做,就讓一個變量的內存地址發生了變化,取回了正確的值。怎麼想都以爲很是詭異,莫名其妙。
這個問題從7.0.0發佈的時候我就發現了,由於這個問題,這一年來我一直在認真考慮轉Java仍是C#的問題。
固然,也許我能夠經過一些內存跟蹤的手段去明確這個問題的根本,但我實在懶得折騰了。
其實PHP7還有一些讓我不太滿意的問題,好比ArrayObject的問題,好比:ArrayObject->item += 1,是沒法觸發offsetSet和offsetGet接口的。這個可能不算bug,也許到php7,關閉了這個特性。
不管如何,我對PHP的態度是,我只是這個語言的使用者,若是你讓我折騰C,我不如去寫Go、Java、C#等等,多了去的選擇。因此若是這個語言自己不可靠,那我真的應該考慮換一個語言了。