Конфликты имен поведений

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
OrionMax
Сообщения: 7
Зарегистрирован: 2016.11.09, 16:20

Конфликты имен поведений

Сообщение OrionMax »

В руководстве написано: Конфликты имен свойств и методов поведений, прикрепленных к компоненту, разрешаются на основе порядка их подключения.
Хотелось бы узнать как это происходит. Если, допустим, в первом поведении есть такой код:

Код: Выделить всё

public function __get($name)
{
    if ($name == 'behavior1') {
        return $name;
    } else {
         return parent::__get($name);
    }
}
 
А во втором:

Код: Выделить всё

public function __get($name)
{
    if ($name == 'behavior2') {
        return $name;
    } else {
         return parent::__get($name);
    }
}
 
То при вызове $model->behavior2 получим UnknownPropertyException?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Конфликты имен поведений

Сообщение ElisDN »

Конфликт - это когда свойства одинаковые. А у Вас здесь разные.
Последний раз редактировалось ElisDN 2016.11.25, 09:28, всего редактировалось 1 раз.
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Конфликты имен поведений

Сообщение maleks »

В доке речь о том, что если на компоненте $component висят 2 поведения
Behavior1 {public $someProperty;}
и
Behavior2 {public $someProperty;}
То при обращении $component->someProperty , обращение будет к св-ву someProperty того поведения, которое в behaviors() идет первым.
Yii2 universal module sceleton - for basic and advanced templates
OrionMax
Сообщения: 7
Зарегистрирован: 2016.11.09, 16:20

Re: Конфликты имен поведений

Сообщение OrionMax »

ElisDN писал(а):Конфликт - это когда свойства одинаковые. А у Вас здесь разные.
Все равно не понимаю... Свойства разные, но вызов свойства приводит к вызову магического метода, имена которых одинаковые в поведениях. Почему после проверки условия в первом поведении не вызывается parent::__get($name)?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Конфликты имен поведений

Сообщение ElisDN »

OrionMax писал(а):Все равно не понимаю...
Тогда забейте.
OrionMax
Сообщения: 7
Зарегистрирован: 2016.11.09, 16:20

Re: Конфликты имен поведений

Сообщение OrionMax »

Проверил. Чтобы сработал __get поведения, нужно накостылить.
Так не работает:

Код: Выделить всё

class Behavior1 extends \yii\base\Behavior
{
    public function __get($name)
    {
        if ($name == 'behavior1') {
            return $name;
        } else {
            return parent::__get($name);
        }
    }
}
Чтобы $model->behavior1 вызвал __get поведения, нужно добавить приватное свойство behavior1 в поведение или приватный метод getBehavior1(). Потому что в Object есть такой метод:

Код: Выделить всё

    
    public function canGetProperty($name, $checkVars = true)
    {
        return method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name);
    }
Притом если имя приватного свойства будет такое же как имя свойства в другом поведении, то получим UnknownPropertyException. Вообщем, как я понял, магические методы в поведениях лучше не использовать.
Аватара пользователя
maleks
Сообщения: 1985
Зарегистрирован: 2012.12.26, 12:56

Re: Конфликты имен поведений

Сообщение maleks »

вообще непонятно зачем вы взялись переопределять магические методы у поведений.
Yii2 universal module sceleton - for basic and advanced templates
OrionMax
Сообщения: 7
Зарегистрирован: 2016.11.09, 16:20

Re: Конфликты имен поведений

Сообщение OrionMax »

maleks писал(а):вообще непонятно зачем вы взялись переопределять магические методы у поведений.
Хотел сделать что-то вроде этого (использовал поведение, потому что нужна поддержка событий):

Код: Выделить всё

class Behavior1 extends \yii\base\Behavior
{
    private $obj;

    public function __get($name)
    {
        $objMethod =  'get' . $name . 'SomeName';
        if (method_exists($this->obj, $objMethod)) {
            return $this->obj->$objMethod();
        } else {
            return parent::__get($name);
        }
    }
}
Если использовать трейт, то все бы сработало. И parent::__get($name) вызвал бы __get базового класса, класса который использует этот трейт. Но в случае использования нескольких трейтов с методом __get, пришлось бы указать какой __get использовать, чтобы избежать конфликтов.
А вот чтобы использовать __get в поведении нужно костылить, что может привести к ошибкам если к модели подключены другие поведения.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Конфликты имен поведений

Сообщение ElisDN »

Если нужны динамические поля, то просто добавьте в поведение метод hasProperty:

Код: Выделить всё

public function __get($name)
{
    if ($name == 'myProperty') {
        return $name;
    } else {
         return parent::__get($name);
    }
}

public function hasProperty($name)
{
    if ($name == 'myProperty') {
        return true;
    } else {
         return parent::hasProperty($name);
    }
} 
и костыли будут не нужны.
OrionMax
Сообщения: 7
Зарегистрирован: 2016.11.09, 16:20

Re: Конфликты имен поведений

Сообщение OrionMax »

ElisDN писал(а):Если нужны динамические поля, то просто добавьте в поведение метод hasProperty:

Код: Выделить всё

public function __get($name)
{
    if ($name == 'myProperty') {
        return $name;
    } else {
         return parent::__get($name);
    }
}

public function hasProperty($name)
{
    if ($name == 'myProperty') {
        return true;
    } else {
         return parent::hasProperty($name);
    }
}
и костыли будут не нужны.
Да, так интересней) Спасибо.

Upd2: Туплю... Действительно, почему бы не переопределить canGetProperty.
Ответить