Question

I've been developing Yii application. And I'm wondering if it's possible to declare in model behavior some kind of "abstract" method. I know that it impossible to use directly following declaration:

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

because we need an instanse of this class. But also I know that Yii is full magic:)

I just want to make owner class to redeclare method from the behavior in obligatory order. Sure, I can use interface in addition to behavior but ...

Sorry if I've missed something to tell or something is not clear. Just ask and I'll try to explain what I mean.

Does anybody know something about this?

Thanks in advance.

UPD

I do understand that Yii is just PHP. It doesn't extend PHP. It is superstructure over it. And it doesn't have multiple inheritance since PHP doesn't.

I do understand behavior method can't be declared using abstract keyword. That is why I have written word "abstract" in quotes. But whatever. I know how behaviors work.

My question was if I can somehow oblige model(e.g. child of CActiveRecord) to declare some method.

For example, for my purposes I can do something like this:

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

Therefore, if I attach this behavior to my model and call method doFantasticThings this method will try to call method prepareForFantastic from model(owner). And if model doesn't have method prepareForFantastic declared new exception will be thrown because non-declared method are called.

Looks like I've answered my question myself :) What do you think about this?

UPD2

Yes, I know that if we don't call "abstract" method we won't know that it is not declared. It is a "charm" of interpretable languages :) We don't know if there is any error untill the code is run. Although, it would awesome if we could know about this as earlier as possible. For example, once instance of FantasticBehavior-class is attached to the model we could throw some child of CException to show what required methods must be declared in model. To achive this we can use something like listed below:

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

}

We need to override method attach from class CBehavior and check if "abstract" methods declared. Method abstractMethods is used to get list "abstract" method.

I don't know if there is attachBehavior event exists. If so, we can use it instead of overriding attach method.

Using this idea Base class for behaviors with "abstract" methods.

What do you think about this?

Maybe in future I'll make extention for Yii and become famous and rich? :))

Was it helpful?

Solution

This might be a little confusing to explain...

No, you cannot "attach" abstract methods to your CActiveRecord model using Yii's Behaviors. All Behavior's do is some clever overrides of __call(), __get() and __set() that give the illusion of multiple inheritance. (This is a good article about it). Behaviors do not provide true "multiple inheritance" support for core language features like abstract classes and interfaces. So if you attach that Behavior and add doSomethingFantastic() to your CActiveRecord class, you will still get an error.

You can, of course, declare abstract Behaviors that other Behaviors extend. So if you created another SuperFantasticBehavior Behavior that extended FantasticBehavior and implemented doSomethingFantastic() in it, you'll be fine. But it won't force you to declare the doSomethingFantastic() method in the CActiveRecord itself.

For a little deeper understanding: The way Yii's CComponent::_call() override is structured, when you call a method it will first see if any of the behaviors have that method, and call the method on the class itself.

Behavior's seem cool at first (mixins!), but sometimes it's just better to remember that PHP is a single class inheritance language and keep is simple. ;)

UPDATE:

The difference is that if you could use abstract methods in this case you'd see a "Class must implement method" error when you try to run your code (any code), and your IDE would highlight the error. This is more of a "compile" time error (not that it really exists in an interpreted lang like PHP).

Instead you'll see a "non-declared method" error (as you mention) at runtime. But you won't see it until that method is actually called, meaning you don't get that nice early warning like an abstract definition would give you. And if that method is never called, you won't get the error, which to means it's not really "obliging" the declaration in the same way an abstract def would.

Sorry if my initial answer was starting out at too basic of a level, I just wanted to be sure there was no misunderstanding. It's an interesting discussion, and made me think more about what an abstract declaration really does. Thanks, and happy coding! :)

Cheers

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top