2010-08-17 46 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; 

    ... 
} 

性状的基本工作原理类似复制/粘贴,因此所有的该特征中的代码将在课程中提供(没有代码重复)。