Я только что столкнулся с неожиданным поведением в отношении черт.
В проекте Symfony 6.2 я использую трейт внутри контроллера. При вызове $this->getUser() или $this->isGranted() на самом деле он будет работать правильно и получит результат пользователя или избирателя, как если бы он был выполнен внутри класса Controller.
Очевидно, что код трейта выполняется в контексте класса Controller, поэтому в этом сценарии атрибуты/методы контроллера доступны внутри трейта.
Это предполагаемое поведение или просто побочный эффект, на который я не должен полагаться?
Псевдокод:
class SomeController extends AbstractController
{
use SomeTrait;
#[Route('/api/some-route', methods:['GET'])]
public function doSomething(){
// code
$this->callTraitMethod();
// code
}
}
trait SomeTrait
{
public function callTraitMethod()
{
// code
$this->getUser(); // works correctly !
// code
}
}
Да, эти термины взаимозаменяемы в Интернете. Атрибуты, свойства, поля... но я с вами согласен.
@Cerad: Можете ли вы дать ссылку на очень четкое определение, которое вы упомянули?
Теперь, читая все комментарии и т. д., и подумав, мне нужно спросить: вас беспокоит использование свойств или методов класса в трейте? В заголовке я читаю свойства, а в коде только методы. Каково/было ваше намерение? @tweekz
@hakre Первоначально название читалось как «использование атрибутов класса», а не свойств. ОП отредактировал вещи после моего первоначального комментария. Отсюда путаница. Я, вероятно, должен удалить свой первый комментарий, но тогда это просто запутает последующие комментарии.
Оба. Мне кажется плохим стилем кодирования ссылки на свойства и/или методы, которые не определены в трейте.
@tweekz: Ах, приятно знать. Потому что у меня сложилось впечатление, что вы столкнулись с проблемами именно с недвижимостью. И код-стиль-правило, которое у вас есть для себя, кажется мне вменяемым для трейтов, но учтите, если рассматривать его строго, вы не можете использовать трейты для шаблонного кода внутренних реализаций. Возможно, вы этого не делаете, и впредь такое правило, естественно, может очень помочь. ИМХО, хороший стиль кода должен запрещать использование трейтов в целом и иметь соответствующие исключения, не ограничивая их.
Я полностью согласен с тем, что этого следует избегать. Но это не то, что вы спросили. На самом деле есть довольно много людей, которые считают, что трейты сами по себе являются плохим стилем кодирования. Я не один из них, но я думаю, что их использование должно быть ограничено.
Да, я пришел с Java, и там почти все четко определено (по крайней мере, косвенно). Так что это был своего рода культурный шок, что мой код все еще работал после рефакторинга его в Trait без явной передачи свойств классов.
Так что, пожалуй, немногое, что можно было бы добавить, это то, что трейты были добавлены в язык PHP, потому что он имеет одиночное наследование. Таким образом, можно совместно использовать больше кода между классами без необходимости перехода на множественное наследование (сталкивается с проблемой алмаза). Не уверен, что трейты вообще существуют в Java.
@hakre Это именно то, для чего я думал, что это было сделано. Однако я не ожидал, что это «слилось». Я могу только представить, сколько непреднамеренного поведения может привести к более сложному коду.
Смотрите последнее предложение в моем ответе ^^. И думаешь: почему бы тебе вместо этого не заняться композицией? Или это было так: Хм, что может означать этот рефакторинг IDE...?






Наблюдаемое вами поведение, когда методы из типажа могут обращаться к $this->getUser() и $this->isGranted(), как если бы они вызывались непосредственно из класса контроллера, является предполагаемым поведением. Это связано с тем, что трейты по существу «слиты» с классом, в котором они используются, и имеют ту же область действия, что и класс.
Когда вы используете SomeTrait в классе SomeController, методы, определенные в трейте, становятся частью класса контроллера, а $this ссылается на экземпляр SomeController, поэтому вы можете без проблем обращаться к $this->getUser() и $this->isGranted() из методов типажа.
Я предполагаю, что кодирование, основанное на реализациях класса, использующего этот признак, не является хорошей практикой. Или он действительно предназначен для такого использования?
@tweekz: Пока вы полагаетесь на интерфейс абстрактного класса, я бы сказал, что это обычная практика, которая выполняется изо дня в день миллионами по всему миру. Вы можете захотеть задаться вопросом, являются ли трейты хорошей практикой, и если вы хотите полагаться на определенные в них шаблоны, то, возможно, это имеет больше смысла, но трейт никогда не является ведущим, а класс, использующий неправильный трейт, - это сломанный класс, а не трейт, полагающийся на реализации класса. Черта просто есть. Смотрите мой ответ, как вы могли бы сделать их более абстрактными, особенно когда вы спрашивали о свойствах и чертах.
@tweekz: Похоже, этот ответ был просто какой-то чепухой, сгенерированной ИИ, просто к вашему сведению. Больше обсуждения здесь: stackoverflow.com/questions/8544171/… - По этой же причине вы не получили ответа от автора на свой отзыв в комментарии.
Очевидно, что код трейта выполняется в контексте класса Controller, поэтому в этом сценарии атрибуты/методы контроллера доступны внутри трейта.
Это предполагаемое поведение или просто побочный эффект, на который я не должен полагаться?
Это предполагаемое поведение, а не побочный эффект.
Используйте (каламбур) синтаксис в качестве мнемоники, класс использует черту. Класс по использованию также управляет переопределениями.
Таким образом, трейт фактически представляет собой только код шаблона.
Вы можете следовать пониманию Барбары Лисков о том, что абстрактный (супер)класс вообще не должен содержать защищенных свойств, и перенести это на черты. Хотя это не соответствует 1:1, вы можете использовать только методы в коде трейтов и никогда не использовать свойства (как без определения, так и без доступа), чтобы лучше проектировать для абстракции при написании кода шаблона.
«Черты копируются и вставляются во время выполнения». (Я не помню, где я услышал это впервые, поэтому, если кто-то помнит, оставьте комментарий.)
Просто для справки в будущем вы можете рассмотреть возможность вызова свойств данных экземпляра класса, а не атрибутов. Атрибуты имеют очень четкое определение. Я предполагаю, что вы могли бы получить доступ к атрибутам из черты, но это было бы необычно. Я упомянул об этом только потому, что это несколько сбивает с толку название.