2

我一直在开发 Yii 应用程序。而且我想知道是否可以在模型行为中声明某种“抽象”方法。我知道不可能直接使用以下声明:

abstract class FantasticBehavior extends CActiveRecordBehavior
{
    public abstract function doSomethingFantastic();
}

因为我们需要这个类的实例。但我也知道 Yii 很神奇:)

我只想让所有者类以强制顺序从行为中重新声明方法。当然,除了行为之外,我还可以使用界面,但是......

抱歉,如果我错过了要说的或不清楚的地方。只要问,我会尽力解释我的意思。

有人知道吗?

提前致谢。

UPD

我明白 Yii 只是 PHP。它不扩展 PHP。它是上层建筑。而且它没有多重继承,因为 PHP 没有。

我确实理解不能使用抽象关键字声明行为方法。这就是为什么我在引号中写了“抽象”这个词。但是无所谓。我知道行为是如何运作的。

我的问题是我是否可以以某种方式强制模型(例如 CActiveRecord 的子代)声明某种方法。

例如,出于我的目的,我可以这样做:

class FantasticBehavior extends CActiveRecordBehavior
{
    public function doFantasticThings()
    {
        $this->owner->prepareForFantastic();
        // some code
    }
}

因此,如果我将此行为附加到我的模型并调用方法 doFantasticThings,此方法将尝试从模型(所有者)调用方法 prepareForFantastic。如果模型没有方法 prepareForFantastic 声明的新异常将被抛出,因为未声明的方法被调用。

看起来我自己已经回答了我的问题:) 你对此有何看法?

UPD2

是的,我知道如果我们不调用“抽象”方法,我们就不会知道它没有被声明。这是可解释语言的“魅力” :) 在代码运行之前,我们不知道是否有任何错误。虽然,如果我们能尽早知道这一点,那就太棒了。例如,一旦FantasticBehavior-class 的实例附加到模型,我们可以抛出一些子对象CException来显示必须在模型中声明哪些所需的方法。为了实现这一点,我们可以使用如下所列的东西:

class FantasticBehavior extends CActiveRecordBehavior
{

    public function attach($owner)
    {

        if(!/*$owner has declared methods list this->abstractMethods*/)
        {
            throw new CAbstractMethodNotDecalared('....');
        }

        parent::attach($owner);     
    }

    public function abstractMethods()
    {
        return array('prepareForFantastic');
    }

}

我们需要覆盖attach类中的方法CBehavior并检查是否声明了“抽象”方法。方法abstractMethods用于获取列表“抽象”方法。

我不知道是否有attachBehavior事件存在。如果是这样,我们可以使用它而不是覆盖attach方法。

将这个想法基类用于具有“抽象”方法的行为。

你怎么看待这件事?

说不定以后我会为Yii做扩展名利双收?:))

4

1 回答 1

2

这可能有点难以解释......

不,您不能使用Yii 的 Behaviors将抽象方法“附加”到您的 CActiveRecord 模型。所有 Behavior 所做的只是对 , 进行一些巧妙的覆盖__call()__get()从而__set()产生多重继承的错觉。(这是一篇关于它的好文章)。行为不为抽象类和接口等核心语言特性提供真正的“多重继承”支持。因此,如果您附加该行为并添加doSomethingFantastic()到您的CActiveRecord类中,您仍然会收到错误消息。

当然,您可以声明其他行为扩展的抽象行为。因此,如果您创建了另一个在SuperFantasticBehavior其中扩展FantasticBehavior和实现doSomethingFantastic()行为,那么您会没事的。但它不会强迫您在其本身中声明该doSomethingFantastic()方法。CActiveRecord

更深入的理解:Yii 的CComponent::_call()覆盖的结构方式,当你调用一个方法时,它会首先查看是否有任何行为具有该方法,然后在类本身上调用该方法。

行为一开始看起来很酷(mixins!),但有时最好记住 PHP 是一种单类继承语言并且保持简单。;)

更新:

不同之处在于,如果您可以在这种情况下使用抽象方法,当您尝试运行代码(任何代码)时,您会看到“类必须实现方法”错误,并且您的 IDE 会突出显示该错误。这更像是一个“编译”时间错误(并不是说它真的存在于像 PHP 这样的解释语言中)。

相反,您会在运行时看到“未声明的方法”错误(正如您所提到的)。但是在实际调用该方法之前您不会看到它,这意味着您不会像抽象定义那样得到很好的早期警告。如果从不调用该方法,您将不会收到错误,这意味着它并没有像抽象 def 那样真正“强制”声明。

抱歉,如果我最初的回答太基础了,我只是想确保没有误解。这是一个有趣的讨论,让我更多地思考抽象声明的真正作用。谢谢,编码愉快!:)

干杯

于 2012-03-01T21:12:09.383 回答