yii2: Behavior event doesn't detach

Behavior event is not detach if handler is Closure.

Simple example:

$obj = new class () extends Component
{
    public $foo = 'foo';
};
$obj->attachBehavior('bar', (new class () extends Behavior
{
    public function events()
    {
        return [
            'barEventOnce' => function ($event) {
                echo $this->owner->foo;
                $this->detach(); // like that I intended to do
            },
        ];
    }
}));

$obj->trigger('barEventOnce'); // it's ok, see "foo"
$obj->trigger('barEventOnce'); // exception, because owner is null

Actually, I did the behavior for a model, the event in which was supposed to work only once. The handler of an event at me also anonymous function, but an event does not get rid and by a repeated call I receive a mistake. It turns out that the behavior got rid, and the event does not, because of here such check in the class Component

if ($event[0] === $handler) {

I replaced Closure with a class function, but was unpleasantly surprised by this behavior. Maybe add this remark to the documentation or fix this error?

Yii version : 2.0.16 PHP version: 5.6/7.1

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 19 (19 by maintainers)

Commits related to this issue

Most upvoted comments

I was thinking more about this on attach:

        foreach ($this->events() as $event => $handler) {
            $this->_attachedEvents[$event] = $handler;
            $owner->on($event, is_string($handler) ? [$this, $handler] : $handler);
        }

And the on detach:

            foreach ($this->_attachedEvents as $event => $handler) {
                $this->owner->off($event, is_string($handler) ? [$this, $handler] : $handler);
            }

These are literally 2-3 lines of code do change/add.

I don’t understand this comment. You can compare objects, but === will return true only when you’re comparing the same instances. The whole point of solution from https://github.com/yiisoft/yii2/issues/17223#issuecomment-479203554 is to keep original instance to use it to === compare.

Yes. That’s even better 😃