[英]Static / Non-Static Method Issue
我正在研究一個簡單的ORM解決方案,並遇到了棘手的情況。 理想情況下,我希望能夠在靜態上下文和對象上下文中使用方法,具體取決於它的調用方式。 我不確定這是否可行,但這就是我的意思:
假設用戶模型想靜態調用where(),這當前工作正常,例如:
$user = User::where('id = ?', 3);
現在,我也支持關系,例如用戶可以擁有消息。 建立此關系后,我只需在用戶模型中存儲消息模型的空白副本並設置外鍵。 例如:
$user -> messages = new Message();
$user -> messages -> foreign_key = 'user_id';
現在,理想情況下,我希望能夠致電:
$user -> messages -> where('unread = ?', 1);
在非靜態上下文中,在此上下文中使用$ this - > foreign_key,以便僅提取外鍵與用戶id匹配的消息。 這種類型的上下文切換在PHP中是否可行? 從靜態上下文對$ this的任何引用都會拋出一個錯誤,因為它是一個靜態方法,並且不應該依賴於$ this(出於顯而易見的原因,當從靜態上下文調用時,$ this將不存在)
這有什么巧妙的方法嗎? 我嘗試重載方法有兩個不同的原型,有和沒有靜態關鍵字,但這引發了重新聲明錯誤。
經過相當多的游戲后,我找到了一種方法,可以在沒有@ drew010提到的Strict Standards
錯誤的情況下使其可行。 我不喜歡它,它感覺很糟糕,但它確實有效,所以無論如何我都會發布。
基本上,我們的想法是讓您想要訪問的方法是private
和static
。 然后定義__call()
和__callStatic()
魔術方法,以便它們調用私有靜態方法。 現在你可能會認為“這不能解決問題,我仍然停留在一個靜態上下文中” - 你只是為了一個小的補充,你可以將$this
附加到傳遞給__call()
實際方法的參數並將其作為方法的最后一個參數獲取。 因此,不是在對象上下文中引用$this
,而是引用第三個參數來獲取對自己實例的引用。
我可能不會很好地解釋這個,只看看這段代碼 :
<?php
class test_class {
private $instanceProperty = 'value';
private static function where ($arg1, $arg2, $obj = NULL) {
if (isset($obj)) {
echo "I'm in an object context ($arg1, $arg2): I can access the instance variable: $obj->instanceProperty<br>\n";
} else {
echo "I'm in a static context ($arg1, $arg2)<br>\n";
}
}
public function __call ($method, $args) {
$method = "self::$method";
if (is_callable($method)) {
$args[] = $this;
return call_user_func_array($method, $args);
}
}
public static function __callStatic ($method, $args) {
$method = "self::$method";
if (is_callable($method)) {
return call_user_func_array($method, $args);
}
}
}
test_class::where('unread = ?', 1);
$obj = new test_class();
$obj->where('unread = ?', 2);
如果不違反PHP標准並以不應該使用的方式使用語言,我想不出任何方法可以做到這一點。
函數是靜態的還是非靜態的。 是PHP允許您以任何方式調用它,但這確實違反了嚴格的標准,並且您可以逃避這樣做的唯一原因是向后兼容舊的PHP 4代碼,其中靜態不作為關鍵字存在。
考慮以下代碼:
<?php
class Test {
protected $_userId;
public function find()
{
if (isset($this)) {
echo "Not static.<br />\n";
} else {
echo "Static.<br />\n";
}
}
}
$t = new Test();
$t->find();
Test::find();
輸出是:
不是靜止的。
靜態的。
但是在啟用錯誤報告的情況下,這是實際輸出:
不是靜止的。
嚴格標准:非靜態方法Test :: find()不應在第19行的test.php中靜態調用
靜態的。
如果將方法聲明為static,則無論調用哪種方式,它都是靜態的。
所以我認為答案是肯定的,你可以使用這種解決方法,但我不推薦它。 如果你想兩種方式,我建議添加兩個方法, public function find()
和public static function findStatic()
。
由於你的代碼要么寫成$obj->find()
或Class::find()
,你可以在我看來輕松使用靜態和非靜態方法,而不是讓一個方法靜態地運行。 為了堅持DRY,我想一種方法可以利用另一種方法來進行實際發現。
很抱歉沒有回答你的問題,但我有一些評論不適合...評論。 你正在做的事情有點不合邏輯。
$user->messages = new Message();
你要創建一個單一的消息中的變量稱為消息 。
你的意思是$user->messages[] = new Message();
?
另外,保護您的類變量。
$user->messages->where('unread = ?', 1);
在這里,您嘗試從用戶消息中進行選擇,這是無稽之談。
你應該做的就像你對User
類所做的一樣:靜態獲取消息,然后將它們分配給你的用戶:
$user->messages = Message::where('unread = ?', 1);
如果需要查找具有特定主鍵的消息,請將其作為參數傳遞給where
方法,該方法可以增強以采用許多子句:
$messages = Message::where(array(
array('unread = ?', 1),
array('id = ?', $message->getID()),
));
我還想添加一個個人注釋:創建ORM是一種很好的學習方式,但如果你正在尋找更嚴肅的東西,我建議你給Doctrine或Propel看一看。
從理論和實踐的角度來看,擁有一個可以從靜態和非靜態上下文中調用的類方法並不是一個好主意。
如果您希望在整個應用程序中實現類/方法的可訪問性,那么閱讀依賴注入,服務容器和依賴注入的編程可能是一個良好的開端。
通過在您的應用程序中實現DI,您很可能不再需要您提到的內容。
我建議調查低谷網絡,你會發現你正在使用的上下文中的靜態調用被避免並被標記為不好的做法。 面向對象編程中的靜態/共享狀態是應該避免的(以及單例模式)。
不要誤解我的意思 - >靜態方法有其目的和好處,但是,你使用它的方式有點過時(盡管一些框架,如Laravel,促進了這種不良做法 - 例如“Facades”和Eloquent)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.