2012-05-08 81 views
3

這是一個普遍的排序問題,但解釋它我會用一個具體的例子。PHP短路評估(好/壞?)

我有一個加載文檔的函數。如果該文檔不存在,它將創建它,如果它存在,它會將其轉換爲JSON數組。我總是希望這個函數返回一個某種類型的數組,無論json_decode()是否存在問題,或者文件不存在。目前,我做這件事是這樣的...

function load($file) { 
    if(! file_exists($file)) { 
     $handle = fopen($file, 'w'); 
     fclose($handle); 
    } 

    $raw = file_get_contents($file); 
    $contents = json_decode($raw, TRUE); 

    return(! $contents ? array() : $contents); 
    //cant use ternary shorthand "?:" in PHP 5.2, otherwise this would be shorter 
} 

現在,有沒有錯,上面的代碼(至少我不覺得有什麼,它工作正常)。不過,我一直在尋找方法來改善我的代碼並在保持完美清晰的同時對其進行壓縮。這個迴歸聲明一直困擾着我,因爲它看起來效率很低。所以今天我開始思考和發生了一些事情。我記得看到mysql教程做了一些connect() or die();的效果,所以我想,爲什麼不json_decode() or array();?這甚至會工作嗎?所以我重寫了我的功能找出...

function load($file) { 
    if(! file_exists($file)) { 
     $handle = fopen($file, 'w'); 
     fclose($handle); 
    } 

    $raw = file_get_contents($file); 
    return json_decode($raw, TRUE) or array(); 
} 

它似乎,它甚至讀取愉快足夠。因此,我的下一輪問題。這是好的做法嗎?我明白,但是會有其他人嗎?它真的有效嗎?或者這是一個有一個快樂結局的錯誤?我得四處看看,發現我問的是短路評估,而不是一個錯誤。這很好知道。我用這個新術語來改進我的搜索,並提出了一些更多的材料。

Blog Entry

Wikipedia

沒有太多,我發現大多數的一切,談到了我詢問總是提到的MySQL連接的方式使用短路。現在,我知道大多數人反對使用術語,但僅僅是因爲它是處理錯誤的一種不雅的方式。這不是我詢問的方法的問題,因爲我不打算使用or die()。有沒有其他的理由不使用它?維基百科似乎認爲是這樣,但只是參考C.我知道PHP是用C編寫的,所以這是絕對有用的信息。但是這個問題在PHP編譯中已經出現了嗎?如果不是這樣,它和維基百科一樣糟糕嗎?

這是維基百科的片段。 「短路會導致現代處理器的分支預測出現錯誤,並且會大大降低性能(一個值得注意的例子是高度優化的射線跟蹤中與軸對齊的盒子相交代碼的光線)[需要澄清]。一些編譯器可以檢測到這種情況併發出更快的代碼,但由於可能違反C標準,並不總是可能的。高度優化的代碼應該使用其他方式來執行此操作(如手動使用匯編代碼)「

什麼你們都在想嗎?

編輯

我調查的另一個論壇,並得到了一些好成績出現。普遍的共識似乎是,這種形式的變量賦值雖然有效,但並不是首選,甚至可能被認爲是現實世界中的不良形式。我會繼續留心,如果有新事物出現,我會更新它。感謝Corbin和Matt提供的信息,尤其是Corbin爲了解決一些問題。 Here的鏈接到論壇帖子,如果你有興趣。

+3

@DaveRandom反對php的人的典型答案 – Matt

+3

在您的原始返回聲明中,爲什麼要烘焙消極? '返回$內容? $ contents:array();'。也不需要父母。 – Madbreaks

+0

@Madbreaks:這實際上是從我之前刪除的一個條件。它最初看起來像'return(!isset($ contents)||!$ contents?array():$ contents);'這可能會讓我更加明白爲什麼它是這樣的,我只是忽略了在我休息時重新定位改變了它。 – mseancole

回答

2

您提出了幾個不同的問題,所以我會盡力解決所有問題。

錯過的分支預測:除非您使用C語言或彙編語言編寫代碼,否則不要擔心。在PHP中,你遠離硬件,因此關於分支預測的想法不會對你有所幫助。無論哪種方式,這將是一個非常微觀的優化,尤其是在開始進行大量字符串分析的函數中。

有沒有其他理由不使用它?維基百科似乎認爲是這樣,但只是參考C.我知道PHP是用C編寫的,所以這是絕對有用的信息。

PHP可能會將其解析爲不同的執行結構。除非你計劃數百萬次運行這個函數,或者你知道這是一個瓶頸,否則我不會擔心。在2012年,我發現使用or進行短路的可能性很小,甚至會導致第十億分之一秒的差異。

至於格式,我發現$a or $b相當醜陋。我的思想不能理解它在if語句中看到的短路。

if (a() || b()) 

對我而言,b()只有在a()不計算爲真時纔會執行。

但是:

return a() or b(); 

不具有相同的清晰度給我。

這顯然只是一個意見,但我會提供兩種選擇,我怎麼可能會寫它(這是,在我看來,一個非常小的更清楚一點):

function load($file) { 
    if (!file_exists($file)) { 
     touch($file); 
     return array(); 
    } 

    $raw = file_get_contents($file); 

    $contents = json_decode($raw, true); 

    if (is_array($contents)) { 
     return $contents; 
    } else { 
     return array(); 
    } 

} 

如果你不」不在乎如果文件實際上被創建,你可以把它一步更遠:

function load($file) { 

    $raw = file_get_contents($file); 

    if ($raw !== false) { 
     $contents = json_decode($raw, true); 
     if ($contents !== null) { 
      return $contents; 
     } 
    } 

    return array(); 

} 

我想真的這些代碼段中歸結爲個人喜好。第二個片段可能是我想要的片段。關鍵路徑可能會更清晰一些,但我覺得它保持簡潔而不犧牲可理解性。

編輯:如果你是一個1-返回每個函數的類型的人,下面可能是一個比較理想一點:

function load($file) { 

    $contents = array(); 

    $raw = file_get_contents($file); 

    if ($raw !== false) { 
     $contents = json_decode($raw, true); 
     if ($contents === null) { 
      $contents = array(); 
     } 
    } 

    return $contents; 

} 
+1

我爲每個函數投票一個return語句。 – Madbreaks

+3

@Madbreaks我期待有人這樣說。如果您儘早解決錯誤案例,我會發現它更加清晰。爲什麼還要通過函數的其餘部分處理錯誤?而且,您可以瀏覽它並立即查看該功能在頂部檢查的內容。 (儘管我提供的替代方案都不是這方面的特例。) – Corbin

+0

我實際上與Madbreaks達成協議。我認爲一個退出點比許多更好。很多人只喜歡一個入口點。它的概念是一樣的。不必跟蹤多個回報意味着我可以更輕鬆地控制什麼退出該功能以及如何處理它。謝謝您的回答。將它改爲'return a()|| b()'對你更有意義?兩者都是有效的,我也更喜歡後面的,我只用'或'來保留前面的例子。 – mseancole

1

凝代碼爲簡約的線條可能的,你可以得到它並不是總是最好的方法,因爲通常壓縮代碼看起來很酷,但通常難以閱讀。如果您對代碼和可讀性有任何疑問,我建議您在代碼中添加一些標準註釋,以便任何人都可以從您的註釋中理解代碼。

在最佳實踐方面,那是見仁見智的,如果你喜歡它,然後去用它,你總是可以稍後再講代碼下的項目的生活,如果需求是

+0

是的,我知道,如果我想澄清一點,我通常會添加評論。我確實喜歡確保我的代碼仍然清晰易讀,這就是爲什麼我不總是濃縮它,只有當我認爲它很容易理解。 – mseancole

0

我喜歡短路聲明是進行單線變量檢查的一種方式。

我喜歡:

isset($value) or $value = 0; 

不是:

if (!isset($value)) { 
    $value = 0; 
} 

但我還沒有在收益直接使用它,這篇文章提出想試試。

可悲的是,它不能正常工作,至少對我來說:

return $data[$key] or $data[1]; 

將返回值1在所有情況下,而我在等一個陣列。

下工程進展順利:

// Make sure $key is valid. 
$data[$key] or $key = 1; 

return $data[$key]; 

但我很驚訝,當$關鍵不在$數據存在PHP不拋出任何錯誤。