PHP中多重继承的解决方法?

时间:2010-08-17 17:54:47

标签: php oop multiple-inheritance

在我的很多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");

我宁愿避免?

或者我可以在包含类中编写'gateway'函数,它对错误对象进行适当的调用,并防止从外部设置错误状态,

class childClass extends parentClass {

    private $error;

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

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

    ...
}

但是这导致(某些)我试图避免的代码重复。

这里的最佳解决方案是什么?我正在尝试为许多对象提供错误状态的功能,以便外部世界可以看到他们的错误状态,重复次数最少。

3 个答案:

答案 0 :(得分: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

也无需在isError()内创建getError()childClass等(因此无需担心代码重复)。只需致电$this->errors->isError()$this->errors->getError()等。如果您仍然想要实施这些方法,请按照以下建议,指定一个界面。

答案 1 :(得分: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();

答案 2 :(得分:1)

从PHP 5.4开始,您可以使用Traits

例如,您可以将Trait称为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;

    ...
}

Traits的工作基本上就像复制/粘贴一样,因此特征中的所有代码都可以在类中使用(没有代码重复)。