2009-08-11 33 views

回答

4

通常,這些方法在與第三方API通信或方法/成員結構不清楚時非常有用。

假設你正在編寫一個通用的XML-RPC包裝器。由於在下載WDL文件之前,您不知道可用的方法,因此使用重載是有意義的。

然後,而不是寫以下內容:

$xmlrpc->call_method('DoSomething', array($arg1, $arg2)); 

您可以使用:

$xmlrpc->DoSomething($arg1, $arg2); 

這是一個更自然的語法。


您也可以像變量對象的方法重載一樣使用成員重載。

您只需要注意一件事:將其僅用於變量結構對象,或僅將其用於獲取和設置器的語法快捷方式。這是有道理的,以保持getter和setter方法在你的類單獨在多個方法的業務邏輯,但並沒有什麼錯用它作爲一種快捷方式:

class ShortcutDemo { 
    function &__get($name) { 
    // Usually you want to make sure the method 
    // exists using method_exists, but for sake 
    // of simplicity of this demo, I will omit 
    // that logic. 
    return call_user_method('get'.$name, $this); 
    } 

    function __set($name, &$value) { 
    return call_user_method('set'.$name, $this, $value); 
    } 

    private $_Name; 

    function &getName() { return $this->_Name; } 
    function setName(&$value) { $this->_Name = $value; } 
} 

這樣,你可以繼續使用您的getter和setter方法來驗證並設置你的數據,並仍然使用語法快捷方式這樣:

$shortcut->Name = 'Hello'; 
0

安德魯沒有提到(或在寫的時候沒有提到)是爲擺脫getter和setter的另一種方法。而不必聲明每個setter和getter這樣的:

$obj->setName("Chacha"); 
$obj->setRep(10000000000000000000000); 

你可以,而不是僅僅做

$obj->Name = "chacha"; 
$obj->Rep = 100000000000000000; 

第二種方法更自然。魔術方法基本上進一步推動了面向對象編程的思想,以及你如何實現一項工作對於外界來說應該不重要。通過魔術方法,它允許你存儲你想要的變量,並讓其他類以自然的方式設置它們。

示例:我可以將所有用戶的帳戶首選項存儲在單個數組中,這樣可以非常輕鬆地迭代以將它全部推送到會話。

如果我沒有爲此使用魔法方法,我要麼必須做一堆或者一堆,這意味着要寫更多的代碼,或者允許直接訪問數組,從而揭示實現,所以我以後不能去改變它。

相反,使用魔術方法,我只是讓他們定期設置變量,我在內部處理。

+0

雖然我不會擺脫getter和setter的。包含各個單獨屬性的業務規則的多個方法通常更容易維護和調試,然後包含一個包含所有屬性的所有業務規則的巨大方法。我只是使用'__get()'和'__set()'作爲快捷方式來調用'getX','setX'。對象重載使用必須僅保留用於變量結構對象。 – 2009-08-11 20:47:37

+0

閱讀我的更新版本。 – 2009-08-11 20:50:23

+0

但是,這並不像C#Get/Set Property那樣工作。至少不那麼靈活,如果你想驗證或確認設置什麼。 – Extrakun 2009-08-11 20:52:57

0

當一個類有isset和取消複雜的規則,你可以使用它的情況。例如,包含變量$ a的類可以是對象或其他資源的數組,並且在未設置時,它們必須執行一些其他功能。

儘管我不確定他們爲什麼允許添加一個新屬性並檢索一個非私有屬性,但是您可以通過調用其他代碼(取決於該屬性的名稱)來更改對象的內部狀態屬性/成員變量被設置。

在某些情況下,這類似於操作符重載在C++

0

郵件轉發功能,當您已經完成的或聚集的對象,其中多態性是不是一種選擇(比方說,您使用的是庫類,你無法控制)。

<?php 

// Class A is final, so we can't make subclasses. 
final class A 
{ 
    public function hello($callback) 
    { 
    echo call_user_func($callback, 'hello world'); 
    } 
} 

// so instead, we make a wrapper class that will take an instance 
// of A as an aggregate 
class B 
{ 
    private $a; 

    public function __construct(A $a) 
    { 
    $this->a = $a; 
    } 

    // this mimics inheritance on the aggregate object 
    // method calls are automatically forwarded to instance of A 
    // if they are valid 
    public function __call($method, $args) 
    { 
    if (method_exists($this->a, $method)) 
    { 
     return call_user_func_array(array($this->a, $method), $args); 
    } 
    throw new Exception("Method [$method] not found."); 
    } 
} 

class C extends B 
{ 
    // This mimics overriding an "inherited" method 
    public function hello($callback) 
    { 
    echo call_user_func($callback, 'bonjour le monde'); 
    } 
} 

$a = new A; 

$b = new B($a); 
$c = new C($a); 

$b->hello('strtoupper'); 
$c->hello('strtoupper'); 
0

該功能實際上是what object oriented programming is all about,在它的發明者艾倫凱的頭腦:對象彼此發送消息,並有可能反應的任何種類的消息。在編譯時固定的方法是有限的(但也是更有效的)這個概念的實現。這就是凱的着名引文「我發明了面向對象的術語,我可以告訴你C++不是我想到的。」來自。

基本上,允許對象到方法反應調用,而不必固定在編譯時的相應的方法實現了此原始的,面向對象的更廣泛的定義。大多數現代「動態」語言都以某種形式支持它。

至於什麼是好的:看看Groovy's Builders一個很好的例子。基本上,它通過將方法名稱本身轉換爲數據來實現非常緊湊的低冗餘語法。

0

的一種方式,這是相當多的發燒友,那我用它來創建一個類似Linq的對象關係管理(ORM)系統。在那裏你可以加載一個數據庫表結構,並將數據(來自數據庫表)作爲一個對象進行操作。

include('blibrary/bLinq.class.inc'); 

$linq = new bLinq(new bLinqSql('mysql://dsn')); 
$r = $linq->from('Users') 
      ->password 
      ->select(); 

其轉換爲下面的SQL:

SELECT `password` from Users; 

在SELECT語句中的password來自重載方法。

結果可用於這樣的:

(array)$r->password; // which outputs an array multiple results of password; 
(string)$r->password; // which outputs a string of the first password hash; 
$r->password[2];  // which outputs a string of the third password hash; 

的要點是,「password」可以在對飛數據庫編程時取代任何其他字段中的字。

0

我使用__get和__set將對象鏈接在一起,例如

$user = new User(); 
echo $user->Profile->views; 

這個(通常)調用一些SQL鏈接users.id = profile.user_id。

0

屬性(如在Python或C#中)。例如,當你使用這樣的事情in Nette,創建一些類,它顯示了一些財產公開:

<?php 
class Foo extends Object 
{ 
    public $bar; 
} 

您可以訪問此屬性自然的方式 - $instance->bar。但是,當你想要做一些驗證等等,你只需要添加getter和setter:

<?php 
class Foo extends Object 
{ 
    private $bar; 

    public function getBar() 
    { 
     return $this->bar; 
    } 

    public function setBar($bar) 
    { 
     if ($bar === NULL) throw new Exception('…'); 
     $this->bar = $bar; 
    } 
} 

而且仍然使用$instance->bar。但是當你做$instance->bar = NULL;,這就像打電話$instance->setBar(NULL);

相關問題