2015-01-03 46 views
0

爲什麼PHP不允許私有常量?爲什麼PHP不允許私有常量?

我知道有解決方法,例如使用私有靜態屬性來代替。

但是,從OOP或軟件設計的角度來看,推理是什麼?

+0

很難說爲什麼。希望其中一位PHP開發人員能夠順利通過。我認爲,自PHP 5.3以來,類常量才存在,所以也許它只是沒有實現*還*。我的猜測是,它不是一個非常有用的功能,因此在心願單中很低。保護方法和屬性對保護常量更有用。 – GolezTrol

+1

@ AlexanderO'Mara這沒有任何意義。我想阻止取決於我的私人常量的人,這樣我可以在晚些時候輕鬆地更改它們,而不會讓用戶感到厭煩。 – PeeHaa

+0

@halfer:還有更多這樣的問題 - 但是這個問題是要求我認爲不同的原因。 – hakre

回答

1

Why doesn't PHP permit private constants?

在PHP常量是接口的部分和接口是公開的,始終(這是一個接口是什麼)。

還請參閱PHP Interfaces

我很確定這是設計方面的原因。

關於在你的問題下的評論,有人想減少常量的可見性以稍後改變它們,我會說這聽起來更像是一個變量,而不是一個不改變它的值的常量。它是不變的。

1

TL,TR

什麼是不實現私有常量的理由?

這是一個很好的問題。

他們真的考慮過這個嗎?

我不知道。

  • 當通過PHP內部郵件列表進行搜索時,我沒有發現任何關於此主題的內容。 除非內部的成員發言,否則我們永遠不會知道。

    關於語言的歷史 - 有點1:1C的方法包裝,有些位來自Perl(regexp),有些位Java(oop) - 有可能這個想法彈出來,同時尋找新的語言特徵。

    我會將「私人常量」的概念與VisualBasic或Java聯繫起來。我懷疑VB對PHP有什麼影響。 VB允許在「模塊」中定義「私有常量」 - 這是默認的訪問範圍。 Visual Basic不允許在接口和命名空間中使用常量(但PHP會)。

    PHP可能包含來自Java的一些OOP概念,但有一個很大的區別:常量是Java中的變量。他們的訪問修飾符/可見性級別是:「公共,私人,最終和靜態」。私人常量聲明如下所示:"private static final String MYCONST = "My Constant";這是OOP - 故事結束。與此相比,PHP的常量訪問感覺更加黑客 - 但它更簡單,你仍然有手頭的解決方法。

  • PHP manual for Class Constants第一個評論是:

    It may seem obvious, but class constants are always publicly visible. They cannot be made private or protected. I do not see it state that in the docs anywhere.

    爲什麼這是明擺着的嗎? 「爲什麼一個班級默認公開而不是私人?」 也許,這是一種缺少語言功能,因爲並非所有班級成員都可以正確隱藏。 他是對的,當你從Java或VB到PHP時,這個問題就會彈出來。

  • 讓我們來看看PHP spec。 PHP實現的當前狀態是:類常量總是公共的和靜態的。所以,一次又一次地贊成Facebook寫這樣的詳細文檔:作者考慮了不同的可視性或訪問控制級別。

讓我們來看看接口,類常量和知名度:

  • 怎樣的概念「常量」,從「私有靜態」有什麼不同?

    靜態變量可以改變,常數不能改變。 您不能將函數的運行時值分配給const(const A = sprintf('foo %s', 'bar');),而是分配給私有靜態變量。

  • 接口可能有常數 - 它們不能被覆蓋。

  • 一個類可能有一個常量 - 可能會被繼承的類/接口覆蓋。

  • 還有一種名爲「常量接口模式」的OOP模式 - 它描述了使用接口來定義常量,並使類實現該接口以實現對這些常量的方便的語法訪問。

    提供了一個接口,以便您可以描述一組函數,然後隱藏實現類中的函數的最終實現。這使您可以更改功能的實施,而不必更改使用方法。存在接口來公開一個API。

    通過在接口中定義常量並通過類實現接口,常量成爲API的一部分。實際上,您正在將實現細節泄漏到API中。這就是爲什麼有些人認爲這是一種反模式,其中包括Joshua Bloch(Java)。

現在,讓我們嘗試合併一些概念,看看它們是否合適。我們假設我們試圖避免上面的批評,然後您需要引入一個語法,它允許對常量進行有限訪問,但隱藏API中的常量。您可以通過可見性級別來訪問「訪問控制」:「公共,私人,受保護,朋友,敵人」。目標是防止包或類的用戶依賴於該包或類的實現的不必要細節。這完全是關於隱藏實現細節,對吧?

「接口」中的「私人常量」呢?

這實際上會解決上面的批評,對嗎? 但接口與「私人」的組合,沒有任何意義。這些概念是相反的。 這就是爲什麼界面不允許「私人」訪問/可見性水平。 而「接口」中的「私有」常量也是互斥的。

那麼在「類」中的「私人常量」呢?

class a { 
     /*private*/ const k = 'Class private constant k from a'; 
    } 

    class b extends a 
    { 
     const k = 'Overridden private constant a::k with Class constant k from b'; 

     const k_a = parent::k; 

     // fatal error: self-referencing constant 
     #const k_selfref = self::k . ' + ' . self::k_selfref; 

     // fatal error: "static::" is not allowed in compile-time constants 
     #const k_staticref = static::k; 
    } 

    // direct static access would no longer work, if private 
    // you need an instance of the parent class or an inheriting class instance 
    echo a::k; 
    echo b::k; 
    echo b::k_a; 

    $obj_b = new b; 
    echo $obj_b::k; 
    echo $obj_b::k_a; 

有什麼好處?

  • 該類中的私有常量不會暴露在API中。這是很好的OOP。

  • 從外部訪問父常量將是類和/或繼承訪問。

    echo a::k,現在可以工作 - 可以用「致命錯誤:嘗試訪問沒有類實例或繼承的私有常量」。

  • (這可能仍然僅在編譯時工作,如果沒有運行時間值賦值給一個常量。但我不知道這一個。)

是否有注意事項?

  • 我們會失去常數的直接靜態訪問。

  • 要求創建一個類的實例,只是爲了訪問常量而浪費資源。直接靜態訪問節省資源,而且很簡單。如果我們引入私人信息,那就失去了,訪問將被綁定到實例。

  • 「私人常量」隱式是「私人靜態常量」。訪問操作符仍然是「::」。

    可能的後續更改將切換到隱式非靜態常量。 這是BC休息。 如果將默認行爲切換爲非靜態,訪問運算符將從「::」更改爲「 - >」。 這建立了一個適當的OOP對象訪問常量,這與Java的「常量作爲具有訪問級別的變量」的概念是可比的。這將有點像這樣:http://3v4l.org/UgEEm。當常量被聲明爲「public static const」時,訪問運算符變爲靜態,對吧?

是效益好到足以實現它?

我不知道。它正在討論中。 我喜歡這兩種:常量靜態訪問,因爲它很簡單,並且「常量作爲變量」和適當的訪問級別的概念。

後多數民衆贊成實施,爲了節省資源,並保持持續快速,每個人都開始(重新)宣佈「公共靜態常量」,刪除該實例的要求和違反OOP)

而且BTW:發現HHVM溢出,同時試驗這個答案的代碼。