2010-08-17 29 views
0

在有很多我的PHP類的,我有這樣的代碼:PHP中的多重繼承的解決方法?

private $strError = ""; 
private $intErrorCode = NULL; 
private $blnError = FALSE; 


public function isError() { 
    return $this->blnError; 
} 

public function getErrorCode() { 
    return $this->intErrorCode; 
} 

private function setError($strError, $intErrorCode = NULL) { 
    $this->blnError = TRUE; 
    $this->intErrorCode = $intErrorCode; 
    $this->strError = $strError; 
} 

的一點是,這樣外部的代碼可以知道,如果一個對象有錯誤狀態,有什麼錯誤的字符串,等等。但在一堆不同的類中使用這個確切的代碼是重複的!

我很想有一個雙擴展名,我可以做

class childClass extends parentClass, error { 
    ... 
} 

,並將這些屬性和方法與生俱來的,但是PHP不支持多重繼承。我在想的是創建一個存在於每個類中的錯誤類。如果我把它公開,我可以直接調用它通過對象

if ($myObject->error->isError()) {...} 

,但不會也做出錯誤狀態從包含類以外的設定,

$myObject->error->setError("I shouldn't be doing this here"); 

我寧願避免?

或者,我可以寫「門戶」包含類的功能,它做了錯誤的對象在適當的調用,防止設置來自外部的錯誤狀態,

class childClass extends parentClass { 

    private $error; 

    public function __construct(...) { 
     ... 
     $error = & new error(); 
     ... 
    } 

    public function isError() {...} 
    public function getError() {...} 
    public function getErrorCode() {...} 
    private function setError() {...} 

    ... 
} 

但導致(一些)我試圖避免的代碼重複。

這裏的最佳解決方案是什麼?我試圖爲許多對象提供錯誤狀態的功能,以便外部世界能夠以最少的重複來看到它們的錯誤狀態。

+2

我的猜測是你可以做一些類似於所有父類繼承的'BaseClass'。這並不高雅,但我能想到的就是這些。 – 2010-08-17 18:01:36

回答

3

使用組合而不是繼承。

class Errors { 

    private $strError = ""; 
    private $intErrorCode = NULL; 
    private $blnError = FALSE; 


    public function isError() { 
     return $this->blnError; 
    } 

    public function getErrorCode() { 
     return $this->intErrorCode; 
    } 

    private function setError($strError, $intErrorCode = NULL) { 
     $this->blnError = TRUE; 
     $this->intErrorCode = $intErrorCode; 
     $this->strError = $strError; 
    } 

} 

現在使用一個專用的實例變量來引用它:

class childClass extends parentClass { 
    private $errors = new Errors(); 
    ... 
} 

private知名度會阻止您引用$errors外的類。

也不需要在childClass內部創建isError()getError()等(因此不需要擔心代碼重複)。只需撥打$this->errors->isError(),$this->errors->getError()等。如果您仍希望要求實施這些方法,請按照下面的建議,指定一個接口。

+2

讓我們在'childClass'中添加一個'interface'來實現'setErrors'和'getErrors' – Gordon 2010-08-17 18:09:36

+1

另一方面,如果你有錯誤類擴展父類,並且所有的子類擴展錯誤類,你就不需要爲一個班輪「private $ errors = new Errors();」在你所有的孩子班上。 (不是說一個更好的解決方案,只是說。) – Chris 2010-08-17 18:12:41

+0

我完全困惑?是不是全部要從課堂外調用錯誤?我想從外面看到班級是否有錯誤,而$錯誤只是跟蹤它的一種方式。我不想從類外引用的* only *是'setError()'。我對嗎?我的意思是,這是班級在內部跟蹤其錯誤的好方法,但在某些時候,我確實希望與外界溝通,而這首先是整個問題 - 找出是否'$ myObject'處於錯誤狀態。 – user151841 2010-08-17 18:28:48

1

你也可以濫用__call魔術方法做同樣的事情:

public function __call($name, array $arguments) { 
    $name = strtolower($name); 
    if (isset($this->methods[$name])) { 
     array_unshift($arguments, $this); 
     return call_user_func_array($this->methods[$name], $arguments); 
    } 
    throw new BadMethodCallException('Method does not exist'); 
} 

請注意,我說的虐待......理想情況下,我覺得不同的架構,而不是所有這些「常見方法「無處不在。爲什麼不使用例外而不是檢查$foo->isError?如果這不合適,爲什麼不裝飾課堂?

class Errors 
    protected $object = null; 
    public function __construct($object) { 
     $this->object = $object; 
    } 
    public function __call($method, array $arguments) { 
     $callback = array($this->object, $method); 
     if (is_callable($callback)) { 
       return call_user_func_array($callback, $arguments); 
     } 
     throw new BadMethodCallException('Method does not exist'); 
    } 
    public function __get($name) { return $this->object->$name; } 
    public function __set($name, $value) { $this->object->$name = $value; } 
    // Your methods here 
    public function isInstance($name) { return $this->object instanceof $name; } 
} 

然後就 「包裝」 您現有的對象在類:

$obj = new Errors($obj); 
$obj->foo(); 
+0

這是一個非常有趣的方法來解決這個問題,我可能會嘗試在我的下一個項目中實現它。我喜歡它! – Chris 2010-08-17 18:40:34

+0

它有一些非常大的缺點。首先,你不能天真地使用接口,因爲它不會實現你的接口(因此'isInstance'方法的原因)。其次,調試可能非常困難,因爲您不確定「裝飾器」或動態方法的確切鏈或順序......第三,它可以爲一些非常有趣的「此方法定義的位置」問題提供幫助。這在某些情況下非常有用(這就是我發佈它的原因)。但要小心你的實施方式...... – ircmaxell 2010-08-17 18:50:45

1

由於PHP 5.4,你可以使用Traits

例如,你可以讓特質稱爲ErrorTrait這樣的:

trait ErrorTrait { 
    private $strError = ""; 
    private $intErrorCode = NULL; 
    private $blnError = FALSE; 


    public function isError() { 
     return $this->blnError; 
    } 

    public function getErrorCode() { 
     return $this->intErrorCode; 
    } 

    private function setError($strError, $intErrorCode = NULL) { 
     $this->blnError = TRUE; 
     $this->intErrorCode = $intErrorCode; 
     $this->strError = $strError; 
    } 
} 

那麼你會像這樣定義你的子類:

class childClass extends parentClass { 
    use ErrorTrait; 

    ... 
} 

性狀的基本工作原理類似複製/粘貼,因此所有的該特徵中的代碼將在課程中提供(沒有代碼重複)。