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

发布于 2024-09-14 22:01:22 字数 1438 浏览 1 评论 0原文

在我的很多 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() {...}

    ...
}

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

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

In a lot of my PHP classes, I have this code:

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;
}

The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!

I'd love to have a dual-extension where I could do

class childClass extends parentClass, error {
    ...
}

And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object

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

but wouldn't that also make its error status settable from outside the containing class,

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

which I would rather avoid?

Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,

class childClass extends parentClass {

    private $error;

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

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

    ...
}

but that leads to (some of) the code duplication that I'm trying to avoid.

What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柠檬色的秋千 2024-09-21 22:01:22

使用组合而不是继承。

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() 等。如果您仍想要求不过,正如下面所建议的,您可以指定一个接口来实现这些方法。

Use composition instead of inheritance.

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;
    }

}

And now use a private instance variable to refer to it:

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

The private visibility prevents you from referencing $errors outside of the class.

There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.

不念旧人 2024-09-21 22:01:22

您还可以滥用 __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();

You could also abuse the __call magic method to do the same thing:

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');
}

Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?

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; }
}

Then just "wrap" your existing object in that class:

$obj = new Errors($obj);
$obj->foo();
断爱 2024-09-21 22:01:22

从 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;

    ...
}

Trait 的工作方式基本上类似于复制/粘贴,因此 Trait 中的所有代码都可以在该类中使用(没有代码重复)。

As of PHP 5.4, you can use Traits.

For example you could make Trait called ErrorTrait like this:

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;
    }
}

Then you would define your child class like this:

class childClass extends parentClass {
    use ErrorTrait;

    ...
}

Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文