2011-04-06 31 views
3

這不是一個關於真實代碼的問題,它只是用於討論。它在我看來,能夠傳遞一個對象作爲一個常量引用是很好的。PHP中的恆定非修改對象引用

$c = Coordinate; 
unsafe_func($c); // this should be ok 
unsafe_func(... constant reference ... $c); // this should fail on write to $c 

我知道的一個選項,以傳似set(clone $c)的對象,它會保留一個副本我原來$c不是unsafe_func()修改,但如果我想什麼有一個對象實例?

我想出了一個包裝類(代碼:https://gist.github.com/904897)使用__set()__get()神奇的方法,每次__set()調用拋出異常。它允許我這樣做:

class CoordinateConst extends stdConst {}; 
unsafe_func(new CoordinateConst($c)); // exception: can not be modified! 

我不喜歡的解決方案是通過引入CoordinateConst,我必須刪除Coordinate typehints。但是,如果我擴展Coordinate類,則不會調用__set()方法來顯示可見屬性。

問題:有沒有更常見的方法來做到這一點,或者你寧願避免這種代碼(通過傳遞對象克隆,包裝unsafe_func調用或其他)?

+0

我對這個問題的想法:一個對象應該自己處理。如果對象允許修改其內部狀態,則需要注意允許這些修改並且內部狀態保持一致。所以這不是你想要解決的問題。您的「不安全」功能似乎進行了整體程序流程中不需要的更改。因此,我會說這個功能已經壞了,需要修復。在這種情況下,您不應該嘗試解決函數對其他代碼的副作用,而應該修復這些副作用。 – deceze 2011-04-06 01:33:37

+0

續。:我知道這是爲了討論,所以這只是我的2美分。只是說你可能永遠不需要像這樣的解決方案。 :) – deceze 2011-04-06 01:37:35

回答

2

您的解決方案有效地防止公共屬性被寫入。座標不會是一個固定的基準,如果它有一個功能,如:

public function setX($x) { 
    $this->x = $x; 
} 

另一種(但取決於你想要多久做更多的代碼),將創建只讀版本類。

我知道在Java和C#中它通常應用於Collections。 C#有一個ReadOnlyCollection<T>,它只是一個包裝/代理,就像你在那裏做的一樣。

所以我的解決問題的方法是創建:

class ReadOnlyCoordinate { 
    private $coordinate; 

    public function __construct(Coordinate $coordinate) { 
     $this->coordinate = $coordinate; 
    } 

    public function getX() { 
     return $this->coordinate->getX(); 
    } 

當然,你可以擴展座標,然後扔上設置任何屬性的功能異常。


然後,在這個問題看整體,如果你不希望協調會員/ setter方法暴露於unsafe_func,那麼也許你只能發送所需的數據。這當然取決於它需要多少座標數據。

例如

unsafe_func($coordinate->getRequiredData()); 

但是如果你有很多它需要的數據,它會變成一件麻煩事。

+0

感謝您的意見。我試圖削減代碼示例,但是如果Coordinate具有修改對象屬性的公共方法,則CoordinateConst(或ReadOnlyCoordinate)必須覆蓋它們。 – 2011-04-06 01:27:30

+0

@Goran Rakic理想地說,理想的屬性應該被封裝,所以不會有任何公共屬性改變。所以設置屬性的公共函數應該是唯一的問題。 – Jacob 2011-04-06 01:32:03