traits и члены класса
1 октября 2011
traits в PHP 5.4 — довольно занятный механизм. Хотя, приведённое ниже в официальном мануале не показывается (возможно, решили перестраховаться), но работает:
trait MyTrait { public $traitVar = 'trait var'; public function test() { echo $this->traitVar; echo $this->classVar; } } class MyClass { private $classVar = 'class var'; use MyTrait; } $c = new MyClass(); $c->test(); echo $c->traitVar;
Комментарии RSS по email OK
Подробнее можешь объяснить, что это и для чего?
@aktuba С помощью данного механизма можно "подмешивать" функциональность из одного класса в другой, таким образом можно предотвратить построение громоздких (и не всегда удобных) иерархий классов и "горизонтально" наращивать функциональность.
У Trait не может быть переменных класса.
Я имею ввиду public $traitVar = 'trait var';
2OZ: это почему это?
А почему это не должно работать? Разработчики писали, что traits — это что-то вроде include, т.е. фактически весь их код подставляется прямо в класс при компиляции
я так понимаю это аналог behaviors ?
Spider, чтобы небыло конфликтов с переменными класса. Подключаться может только поведение, то есть методы. Но не сущности.
Максим, не совсем. Есть существенные отличия. Behavior более функционален в плане реюза кода, поэтому из Yii2 мы их не выпилим точно.
OZ, приведённый выше код отлично работает на бете 5.4.
Как бы то ни было, это не правильно и это не будет работать в релизе. Traits с переменными класса ничем не отличаются от обычных классов. Сборник методов не может иметь своих полей. Trait это сборник методов - не больше.
OZ, ещё как отличается. Переменные в трейте — это переменные класса, к которому трейт цепляется, а не переменные самого трейта. У трейта нет состояния, нет экземпляра.
Trait не знает, к какому классу он будет добавлен. Trait это набор методов, а не сущность и не статический класс, поэтому само объявление переменной внутри Trait лишено логики.
OZ, мы фактически об одном и том же говорим. Про «перестраховаться» я не зря писал. Возможно, в релизе и уберут. А может и нет…
Почему? методы же должны где-то хранить состояния того что они делают? иначе было бы достаточно статического класса или функции чтобы что-то делать, зачем это в класс примешивать? Поэтому $traitVar тут как раз к месту, а вот $classVar из trait - да не хорошо...
если не убедил вот пример:
Если в trait нельзя объявлять переменные, то зачем он такой нужен в классе? Достаточно интерфейса и немного копипасты... В любом случае $this->classVar из trait будет работать, даже если захотят - не так просто это запретить.
ну если переменные уберут - можно так, но первый вариант как-то лучше смотрится.
White-Shadow, нет, методы не должны хранить своё состояние, потому что Trait это не объект, у него нет состояния. "и немного копипасты..." - чтобы эту грязь убрать, и были созданы traits.
Trait сам по себе абстрактная штука - у него и методов нет если так посудить, но если его куда-то примешали - то там уже может быть объект и его состояние и методы и т.п., то есть Trait рассматривается в рамках этого объекта, он "наделяет" объект некоторым поведением и для этого ему может потребоваться хранить какие-то значения в полях класса.
то есть Trait - это законченный кирпичик для класса (поведение) которые требуется и другим класса, собственно кроме ActiveRecord - мне примеры и не приходят в голову. Еще разве что синглтоны, фабрики и т.п. кстати self в trait - класс куда его примешали...
White-Shadow, Trait может пользоваться переменными класса, в который его примешивают, но не должен вносить переменные. В trait нет инструмента разрешения конфликтов имён переменных (а конфликтов методов - есть).
Помечтаем :) :
В общем-то это в Yii и сейчас есть.
Sam
а что показывает Reflection MyClass'a?
White-Shadow, для trait-а:
Для метода trait-а:
Ну и из класса, естественно, трейты можно получить через ReflectionClass::getTraits.
вот же есть RFC, в котором написано как оно планировалось, что будет работать: https://wiki.php.net/rfc/traits
Igor, RFC не обязательно соответствуют действительности. Тот, на который вы ссылаетесь, написан в 2008-м. Первый патч, добавляющий трейты сделан в начале 2009-го. Два года всё-таки прошло.
Да, он был заменен на "Horizontal Reuse" https://wiki.php.net/rfc/horizontalreuse Который был обновлен в этом году.
Там написано, что при любом использовании свойств будет генерироваться E_STRICT (1), а при несоответствии объявления будет fatal error. Я не согласен с тем, что про такой вариант можно сказать "работает".
(1) In all other cases, i.e., when the definitions are identical, an E_STRICT notice is shown to raise awareness about the potentially problematic, and discouraged use of properties.
OZ, я вообще не очень согласен с тем, что это trait, а не полноценный mixin.
Кстати, если лень ставить php 5.4, чтобы экспериментировать, можно воспользоваться вот этим сервисом: http://codepad.viper-7.com/kadPmP
ru2.php.net/manual/en/language.oop5.traits.php
Properties
Properties conflict
Собственно уже могут быть, так что пункт 2 комментария №5986 можно отказаться, мне так кажется :)