Использование свойств класса внутри трейта

Я только что столкнулся с неожиданным поведением в отношении черт.

В проекте 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 23.07.2023 14:17

Да, эти термины взаимозаменяемы в Интернете. Атрибуты, свойства, поля... но я с вами согласен.

tweekz 23.07.2023 16:24

@Cerad: Можете ли вы дать ссылку на очень четкое определение, которое вы упомянули?

hakre 23.07.2023 17:02

Теперь, читая все комментарии и т. д., и подумав, мне нужно спросить: вас беспокоит использование свойств или методов класса в трейте? В заголовке я читаю свойства, а в коде только методы. Каково/было ваше намерение? @tweekz

hakre 23.07.2023 17:19

@hakre Первоначально название читалось как «использование атрибутов класса», а не свойств. ОП отредактировал вещи после моего первоначального комментария. Отсюда путаница. Я, вероятно, должен удалить свой первый комментарий, но тогда это просто запутает последующие комментарии.

Cerad 23.07.2023 17:27

Оба. Мне кажется плохим стилем кодирования ссылки на свойства и/или методы, которые не определены в трейте.

tweekz 23.07.2023 17:27

@tweekz: Ах, приятно знать. Потому что у меня сложилось впечатление, что вы столкнулись с проблемами именно с недвижимостью. И код-стиль-правило, которое у вас есть для себя, кажется мне вменяемым для трейтов, но учтите, если рассматривать его строго, вы не можете использовать трейты для шаблонного кода внутренних реализаций. Возможно, вы этого не делаете, и впредь такое правило, естественно, может очень помочь. ИМХО, хороший стиль кода должен запрещать использование трейтов в целом и иметь соответствующие исключения, не ограничивая их.

hakre 23.07.2023 17:41

Я полностью согласен с тем, что этого следует избегать. Но это не то, что вы спросили. На самом деле есть довольно много людей, которые считают, что трейты сами по себе являются плохим стилем кодирования. Я не один из них, но я думаю, что их использование должно быть ограничено.

Cerad 23.07.2023 17:42

Да, я пришел с Java, и там почти все четко определено (по крайней мере, косвенно). Так что это был своего рода культурный шок, что мой код все еще работал после рефакторинга его в Trait без явной передачи свойств классов.

tweekz 23.07.2023 17:53

Так что, пожалуй, немногое, что можно было бы добавить, это то, что трейты были добавлены в язык PHP, потому что он имеет одиночное наследование. Таким образом, можно совместно использовать больше кода между классами без необходимости перехода на множественное наследование (сталкивается с проблемой алмаза). Не уверен, что трейты вообще существуют в Java.

hakre 23.07.2023 17:54

@hakre Это именно то, для чего я думал, что это было сделано. Однако я не ожидал, что это «слилось». Я могу только представить, сколько непреднамеренного поведения может привести к более сложному коду.

tweekz 23.07.2023 17:56

Смотрите последнее предложение в моем ответе ^^. И думаешь: почему бы тебе вместо этого не заняться композицией? Или это было так: Хм, что может означать этот рефакторинг IDE...?

hakre 23.07.2023 17:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
12
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Наблюдаемое вами поведение, когда методы из типажа могут обращаться к $this->getUser() и $this->isGranted(), как если бы они вызывались непосредственно из класса контроллера, является предполагаемым поведением. Это связано с тем, что трейты по существу «слиты» с классом, в котором они используются, и имеют ту же область действия, что и класс.

Когда вы используете SomeTrait в классе SomeController, методы, определенные в трейте, становятся частью класса контроллера, а $this ссылается на экземпляр SomeController, поэтому вы можете без проблем обращаться к $this->getUser() и $this->isGranted() из методов типажа.

Я предполагаю, что кодирование, основанное на реализациях класса, использующего этот признак, не является хорошей практикой. Или он действительно предназначен для такого использования?

tweekz 23.07.2023 16:22

@tweekz: Пока вы полагаетесь на интерфейс абстрактного класса, я бы сказал, что это обычная практика, которая выполняется изо дня в день миллионами по всему миру. Вы можете захотеть задаться вопросом, являются ли трейты хорошей практикой, и если вы хотите полагаться на определенные в них шаблоны, то, возможно, это имеет больше смысла, но трейт никогда не является ведущим, а класс, использующий неправильный трейт, - это сломанный класс, а не трейт, полагающийся на реализации класса. Черта просто есть. Смотрите мой ответ, как вы могли бы сделать их более абстрактными, особенно когда вы спрашивали о свойствах и чертах.

hakre 23.07.2023 16:54

@tweekz: Похоже, этот ответ был просто какой-то чепухой, сгенерированной ИИ, просто к вашему сведению. Больше обсуждения здесь: stackoverflow.com/questions/8544171/… - По этой же причине вы не получили ответа от автора на свой отзыв в комментарии.

hakre 24.07.2023 09:17

Очевидно, что код трейта выполняется в контексте класса Controller, поэтому в этом сценарии атрибуты/методы контроллера доступны внутри трейта.

Это предполагаемое поведение или просто побочный эффект, на который я не должен полагаться?

Это предполагаемое поведение, а не побочный эффект.

Используйте (каламбур) синтаксис в качестве мнемоники, класс использует черту. Класс по использованию также управляет переопределениями.

Таким образом, трейт фактически представляет собой только код шаблона.

Вы можете следовать пониманию Барбары Лисков о том, что абстрактный (супер)класс вообще не должен содержать защищенных свойств, и перенести это на черты. Хотя это не соответствует 1:1, вы можете использовать только методы в коде трейтов и никогда не использовать свойства (как без определения, так и без доступа), чтобы лучше проектировать для абстракции при написании кода шаблона.

«Черты копируются и вставляются во время выполнения». (Я не помню, где я услышал это впервые, поэтому, если кто-то помнит, оставьте комментарий.)

Другие вопросы по теме