Геттеры и сеттеры - насколько они нужны в моделях

StalkerClasses

Новичок
В Symfony есть геттеры и сеттеры в моделях.
А вот в Laravel их нет. Здесь вроде это как динамические атрибуты.

Насколько они вообще эти геттеры и сеттеры играют роль большую?
 

fixxxer

К.О.
Партнер клуба
Если я отвечу «нет», ты подумаешь, что надо не $entity->[gs]etFoo(), а $entity->foo.
Что неверно: не надо ни то, ни другое.

Распространено заблуждение, что публичные свойства нарушают инкапсуляцию, а геттеры и сеттеры ее обеспечивают: вон, в Википедии так написано. На самом деле оба варианта нарушают инкапсуляцию, потому что внешнему коду не должно быть никакого дела до внутренней структуры объекта - ни напрямую, ни опосредованно. В ООП объекты взаимодействуют друг с другом, вызывая методы в соответствии с контрактами. Гетеры и сеттеры - это такой самообман - как будто методы есть (вот же они). Есть-то есть, только архитектура как была процедурной, так и осталась.

Но геттеро-сеттерный подход (хоть с явными геттерами-сеттерами, хоть через магию, как в Laravel)очень распространён, поскольку проектирование моделей таким образом, в виде, по сути, структур данных (это называется anemic models) намного меньше нагружает головной мозг, чем полноценный ООП-подход. Если такого подхода все же придерживаться, то нет абсолютно никакой разницы.
 
Последнее редактирование:

Dreammaker

***=Ф=***
полноценный ООП-подход
Есть ли возможность, как-то теоретически поднять уровень в этом направлении в привязке к PHP? Что-то типа курсов на Udemy,курсере, с практическими примерами? К сожалению, большинство примеров по ООП - это машина, колёса и т.д., к реальному миру никакого отношения не имеющие. :(
 

Adelf

Administrator
Команда форума
Есть ли возможность, как-то теоритически поднять уровень в этом направлении в привязке к PHP? Что-то типа курсов на Udemy,курсере, с практическими примерами? К сожалению, большинство примеров по ООП - это машина, колёса и т.д., к реальному миру никакого отношения не имеющие. :(
Я скоро допереведу на русский свою книгу и выложу бесплатно. там есть довольно много про ООП. https://adelf.tech/2019/architecture-of-complex-web-applications
 

Dreammaker

***=Ф=***
Совсем я уже разучился писать, исправил :)

Я скоро допереведу на русский свою книгу
Спасибо, буду ждать. Заодно и гляну бесплатный семпл на досуге на английском.
> I have worked with a lot of projects which was written by usual "everything in controller" way and when they become to grow their support complexity grows exponentially.
Очень знакомо :)
 

fixxxer

К.О.
Партнер клуба
Есть ли возможность, как-то теоретически поднять уровень в этом направлении в привязке к PHP? Что-то типа курсов на Udemy,курсере, с практическими примерами? К сожалению, большинство примеров по ООП - это машина, колёса и т.д., к реальному миру никакого отношения не имеющие. :(
Есть литература. Обычно на примере Java или C#, но это не имеет значения, на PHP все точно так же (дженериков разве что не хватает, но это не страшно, прекрасно можно обойтись без них).
Курсов таких не знаю.

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

StalkerClasses

Новичок
Если я отвечу «нет», ты подумаешь, что надо не $entity->[gs]etFoo(), а $entity->foo.
Что неверно: не надо ни то, ни другое.

Распространено заблуждение, что публичные свойства нарушают инкапсуляцию, а геттеры и сеттеры ее обеспечивают: вон, в Википедии так написано. На самом деле оба варианта нарушают инкапсуляцию, потому что внешнему коду не должно быть никакого дела до внутренней структуры объекта - ни напрямую, ни опосредованно. В ООП объекты взаимодействуют друг с другом, вызывая методы в соответствии с контрактами. Гетеры и сеттеры - это такой самообман - как будто методы есть (вот же они). Есть-то есть, только архитектура как была процедурной, так и осталась.

Но геттеро-сеттерный подход (хоть с явными геттерами-сеттерами, хоть через магию, как в Laravel)очень распространён, поскольку проектирование моделей таким образом, в виде, по сути, структур данных (это называется anemic models) намного меньше нагружает головной мозг, чем полноценный ООП-подход. Если такого подхода все же придерживаться, то нет абсолютно никакой разницы.

Вот допустим где-то в коде идет обращение к свойству:
$laravelRow = получить записи -> условие -> выбрать()
$laravelRow->myproperty;

И если нет такого свойства - то ошибки не будет на тех настройках что в коробке. В том-же Yii выскочит ошибка. А в Symfony если нет геттера - 100% будет ошибка в коде.
 

fixxxer

К.О.
Партнер клуба
$row - это не модель, это структура строки в базе данных.
Когда ты пишешь $row->property, ты программируешь в процедурном стиле:

$row = selectTableRow('users', 'id = 1');
$row->email = $new_email;
updateTableRow('users', 'id = 1', $row);

В случае, если это все обертывается в классы - это получается Table Gateway, который по сути процедурный подход, обернутый в классы. От того, каким образом ты обернешь - сделаешь публичные свойства, сделаешь геттеры/сеттеры, или сделаешь магию __get/__set - ничего принципиально не меняется, это вопрос конкретной реализации.

То, что в Laravel и Yii называется моделями, ими в строгом смысле слова не является. Их _можно_ использовать как модели, но в этом случае ты никогда не должен писать $user->email. Только $this->email внутри класса User.

В Symfony ты можешь добавить геттеры и сеттеры, чтобы получить аналог $user->email и свести все к Table Gateway. А можешь не писать, и делать полноценные ООП-модели.

Есть, конечно, еще Read Models, которые по сути своей иммутабельные read only структуры - там ты можешь написать $user->email или $user->getEmail() - но не можешь написать $user->email = $newEmail или $user->setEmail($newEmail). Конкретно в PHP тут обычно появляются геттеры по той причине, что в PHP нельзя средствами языка сделать readonly-свойство (есть вариант с магией через __get, но у него свои недостатки - придется описывать свойства в phpdoc, иначе IDE ничего не будет знать о структуре). Те модели, которые в Laravel и Yii, можно использовать как Read Models, если ограничиться только чтением свойств - но тут вознкикает проблема с тем, что Read Models обычно больше одной на одну сущность.
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
в евангелии настоящего ООП есть два пробела: как простые данные из грядки, обычные строки в массиве из базы или _POST, попадают в святую Модель без грешных сеттеров и публичных свойств - и как потом без геттеров они уходят в браузер?

если для вывода все в итоге сводится к __toString(), то со вводом намного интереснее, yii-шный $model->setAttributes() - тот же сеттер, только оптом,
рассказывайте уже про DTO, VO и read-модели
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
о, вот и события :)
давай подробнее - что такое изменения, на которые модель создает объекты типа "событие"?

оно ж непонятно, откуда в вычислительном процессе скрипта, который живет десятые доли секунды, возникают некие изменения...
в JS понятно: кликнул юзер по кнопке - событие, а в php?
 

fixxxer

К.О.
Партнер клуба
как простые данные из грядки, обычные строки в массиве из базы или _POST, попадают в святую Модель без грешных сеттеров и публичных свойств
В ООП данные не попадают откуда-то куда-то. В ООП объекты вызывают методы друг друга в соответствии с их контрактами.

Сама такая постановка вопроса говорит о процедурном подходе.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@fixxxer да, но у нас на входе процедурный $_POST или такой же скалярный php://input,
у нас не java, никакого application server, во входных данных нет никаких объектов,

тем, кто задает вопрос про геттеры, надо понять именно этот момент
 

fixxxer

К.О.
Партнер клуба
но у нас на входе процедурный $_POST или такой же скалярный php://input
У нас на входе HTTP-запрос с его payload-ом. Там никакого кода нет, чистые данные. Как мы их интерпретируем - это уже вопрос архитектуры.
Для упрощения можно рассмотреть частный случай с JSON-RPC, если уж так мешает инерция мышления.

Модель отвечает событиями на изменения. По событиям строятся модели ответа.
Это один из вариантов. Его преимущества ясны после определенного бэкграунда с DDD-штуками, но к нему еще надо прийти.

Для начала надо осознать, что, если мыслить объектами, в сущность не попадают никакие там строки из $_POST, и что все, что мы делаем - это вызываем методы объектов. А в сущности, спроектированной разумно, методы отражают бизнес-действия, а не внутреннюю ее структуру (иначе мы нарушаем инкапсуляцию). Дальше мыслим последовательно. Мы уже определились, что не хотим нарушать инкапсуляцию и выпячивать состояние сущности наружу. В качестве первого шага можно, например, договориться, что модель умеет экспортировать свое состояние в виде некоторого readonly immutable value object...
 

Вурдалак

I'd like to model your domain
давай подробнее - что такое изменения, на которые модель создает объекты типа "событие"?
Если отвечать на твой вопрос как сделать так, чтобы не было геттеров — то на любое изменение, aka event sourcing.

Ну а так, на практике через рефлексию достают, потому что на уровне инфраструктуры на модель смотрят немного иначе. Для инфраструктуры модель — это какая пачка-то с данными.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
предлагаю снять наши короны, и как-то попроще писать такие важные вещи,
потому что все доки по laravel/yii/etc - это процедурный подход с сеттерами, а как эта строка на входе становится событиями в ООП - совершенно непонятно

вот JSON-RPC - хороший пример, спасибо

и вот он, наш value object, в него пишутся данные из _POST, когда отвалидируются, с ним работают объекты модели,
логики в нем нет,
цель существования Value Object - когда мы его наполняем данными в модели и передаем в ответе из одного объекта модели в другой, мы уверены в валидности и консистентности данных,
у VO и публичные поля могут быть
 
Последнее редактирование:

Вурдалак

I'd like to model your domain
предлагаю снять наши короны, и как-то попроще писать такие важные вещи,
потому что все доки по laravel/yii/etc - это процедурный подход с сеттерами, а как эта строка на входе становится событиями в ООП - совершенно непонятно
Ну тут вопрос что это было за действие, а не какой там тип данных.
Если это было действие «забанить», а строка — причина бана, то событие будет совершенно логично называться типа FooWasBanned.

Мы постоянно возвращаемся к этому обсуждению: складывается впечатление, что некоторые то и делают, что обновляют какие-то поля в модели. У вас дизайнер, наверное, по инерции из начала нулевых везде CRUD-формы рисует. Или как это можно объяснить?
 

fixxxer

К.О.
Партнер клуба
JSON-RPC - хороший пример
Это не JSON-RPC хороший пример, это REST все неправильно понимают и используют там, где он неуместен. А он уместен в весьма небольшом количестве частных случаев, когда речь идет о синхронизации состояний. Там даже в названии ST - это State Transfer.

Если даже писать как 15 лет назад, с отправкой POST-запросов напрямую на scriptName.php, никто не мешает считать scriptName методом, а $_POST - аргументами метода.
 
Сверху