Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 19

Пример выглядит странным :)

Фронт/внешний сервис должен понимать, что юзера нет по имени Unknown? Такое себе. Разумнее вернуть им 404 и пусть там разбираются.

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

public function map(callable $fn): Maybe
{
  return $this->value === null ? $this : self::just($fn($this->value));
}

Если уже "nothing", нового не надо же?!

Пример, настолько "выдуманный" что так и не показывает зачем это надо, а наборот доказывает что это код без монады будет проще и быстрее.

public function getUserData(Request $request, UserRepository $userRepository): JsonResponse
{
  $email = $request->get('email');
  $maybeUser = $userRepository->getUserByEmail($email);

  $userData = $maybeUser
    ? call_user_func(fn(User $user) => [
        'name'  => $user->getName(),
        'email' => $user->getEmail(),
      ], $maybeUser)
    : [
        'name'  => 'Unknown',
        'email' => 'Unavailable',
      ];

  return $this->json($userData);
}

Скорее уж лучше написать:


$user = $userRepository->getUserByEmail($email);

return new JsonResponse([
    'name' => $user?->getName() ?? 'Unknown',
    'email' => $user?->getName() ?? 'Unavailable',
]);

Как минимум читаемее будет

Да пример очень не удачный, но имхо и это выглядит как «fluent interface vs тернарник», что как будто вообще смысла не имеет, ведь как только нужно сделать больше одного действия, тернарник станет, имхо, нечинаемым нечто

$userData = $maybeUser
  ->map($smthBeforeConvert)
  ->map($entityToApi)
  ->map($smthAfterConvert)
  ->getOrElse($userStub)
;

В чём принципиальное отличие от?


$userData = $userStub;

if ($maybeUser !== null) {
  $smthBeforeConvert($maybeUser);
  $entityToApi($maybeUser);
  $smthAfterConvert($maybeUser);

  $userData = $maybeUser;
}

А ни в чем, в этом и цимес) сугубо вкусовщина)

Просто изначальный заголовок «попрощайтесь с проверками на null» и способ из статьи раскрывается когда больше 1 условия надо проверить / больше 1 действия сделать, иначе вот мы снова к исходному вернулись.

Все к тому что изначальный пример в статье вымученный и не показывающий преимуществ.

Мне кажется, подобное актуально, когда в языке нет строгой типизации (в первую очередь) и нет конструкций, обеспечивающих удобное взаимодествие с нуллами.


Например в Java, где любой объект может быть как инстансом, так и null, и язык на уровне типов не обеспечивает гарантии того, что объект является корректным инстансом. Поэтому, в Java намного практичнее было бы использовать подобные конструкции, т.к. они предоставляют безопасный инструмент для работы с nullable объектами.


Если говорить про PHP, то этот язык при работе с nullable-объектами более строгий и на уровне типов гарантирует то, что объект не является null. Поэтому и смысла меньше.


// class Example

public Some obj = null; // Java: OK

public Some $obj = null; // PHP: TypeError

Во-вторую очередь, операторы ?->, ?? и проч. позволяют удобно работать с nullable-объектами, поэтому смысла в подобных монадах становится ещё меньше. Например optional:


optional($objectOrNull)->safeMethodCall(); // null | method_result

// vs.

$objectOrNull?->safeMethodCall(); // null | method_result

Как то я нить потерял, операторы ?->?? это безусловно отличные вещи и мне нравится, что можно наконец сделать просто

$userData = ($userRepository->getUserByEmail($email)
  ?->safeMethodCall()
  ?->anotherSafeMethodCall()
  ?->andAnotherSafeMethodCall()) ?? $userStub;

вместо

$userData = $userRepository->getUserByEmail($email);
if ($userData !== null) {
  $userData = $userData->safeMethodCall();
}
if ($userData !== null) {
  $userData = $userData->anotherSafeMethodCall();
}
if ($userData !== null) {
  $userData = $userData->andAnotherSafeMethodCall();
}
if ($userData === null) {
  $userData = $userStub;
}

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

Не проще PHPStan настроить построже чтобы он заставлял обрабатывать nullable значения? Это предотвратит исключения и не повысит порог входа надуманными абстракциями.

Я конечно мало что понимаю в этом вашем Symfony, хотя и работаю с PHP с 2001 года и чего только и на чём только не писал. Заинтересовался словом "монада" применительно к PHP. Это базовая конструкция в изначально функциональных языках программирования, тут же она выглядит как сова, натянутая на глобус.

Вам действительно нравится эмулировать на PHP новомодные подходы в программировании или кто-то сверху заставляет? Вот чего я понять не могу. Почему надо создать миллиард мелких хитропродуманных классов, вместо того, чтобы написать простой лаконичный, быстрый и понятный код, возможно даже вообще без использования классов?

Понимаю, это старый холивар. Вопрос больше риторический, чем вопрос.

Нуууу, монады - далеко не «новомодный подход в программировании»

Почему надо создать миллиард мелких хитропродуманных классов вместо того, чтобы написать простой лаконичный, быстрый и понятный код, возможно даже вообще без использования классов?

Потому что «простой лаконичный, быстрый и понятный код, возможно даже вообще без использования классов» в 90% случаев понятный только его автору и только в течении ограниченного времени. Как только есть маломальски крупная команда это все превращается в кошмар. Этот «миллиард мелких хитропродуманных классов» нужен чтобы следовать общепринятым паттернам в проектировании и появились они не на пустом месте, а именно для облегчения сопровождения продукта, в том числе и в дальнейшем.

Прям так и представляю человека, который пришел в проект, увидел этот «понятный код» и либо онбордится значительно дольше, чем мог бы, либо со всем известной цитатой из «Очень страшное кино 2» переходит в другой проект/уходит (возможен третий вариант, вида «о, так можно не стараться и фигачить как фигачится» и ситуация станет еще хуже). Проходил этот путь дважды и не рекомендую, кроме случаев когда вытянуть архитектуру и есть личная цель.

Мне наоборот кажется, что достигнуть понимания во всех этих суперхитропродуманных классах без постоянной проверки "что же там внутри" практически невозможно. Вот написали вы отличную "монаду", но для того, чтобы её понять (не по описанию, а именно - что конкретно она делает) придётся заглянуть в её код, и, скорее всего, не один раз. А учитывая, что всё это разбросано по папкам - придётся открыть не один файл.

Короче, это палка о двух концах.Сложный навороченный фреймворк вроде Symfony - это попытка отойти от PHP как такового и создать "более другой" язык на его основе, который с одной стороны чем-то удобен, потому что позволяет нивелировать некоторые недостатки Plain PHP, а с другой стороны добавляет кучу новых определений и условностей, которым программист должен научиться и следовать, причём в отличие от Plain PHP, правила в котором придумали авторы PHP и поэтому они крайне жёстко стандартизированы, в Symfony, Laravel, CodeIgniter... продолжите список сами все эти правила придуманы простыми людьми и постоянно меняются от команды к команде, чем ввергают любого новичка в проекте в ужас, ибо в прошлых проектах правила были другие и ему теперь придётся снова адаптироваться/переучиваться.

В этом плане был немало удивлён, начав работать с другими технологиями, что для веб-приложений в Nodejs, например, существует ровно один фреймворк (несколько других, малоизвестных, опустим) - это Express. И больше просто не нужно, ибо он покрывает 99% всех потребностей и расширяем за счёт простых плагинов. В Python примерно ту же роль играет Django. Я не очень силён в Python, но практически не слышал о других, из чего могу сделать вывод, что он также покрывает бОльшую часть всех потребностей.

Почему в PHP существует такой мегагигантский зоопарк всяких фреймворков?

правила в котором придумали авторы PHP и поэтому они крайне жёстко стандартизированы

Нууу, неоднородность стандартной библиотеки php это уже притча во языцех, а новые стандарты существуют во многом благодаря psr-fig.org - комьюнити.

Почему в PHP существует такой мегагигантский зоопарк всяких фреймворков?

В php как раз нет зоопарка фреймворков - Symfony/Laravel, причем работают во многом на общих компонентах, иное, будь то околомертвый (только предположение) CodeIgniter, все никак не возродившийся yii или заочно любимый мной spiral - довольно редковстречаются.

для веб-приложений в Nodejs, например, существует ровно один фреймворк (несколько других, малоизвестных, опустим) - это Express

https://github.com/vanodevium/node-framework-stars - nest, meteor, strapi - настолько малоизвестны, что в IDE от JetBrains есть их поддержка bundled плагинами от самих JB)

В Python примерно ту же роль играет Django

Django - Symfony мира python (насколько я знаю от общения с python разработчиками) и у них есть и «свой Laravel» - Flask. Bottle, tornado, pyramid и другое мне неизвестно какую нишу занимают.

О дааа, раньше я видел эту сову, натянутую на глобус на шарпе, теперь и до пхп добралось. Абстракция ради абстракции.

А до этого на TypeScript, ага.

Не удержался, мне кажется это не тот велосипед

Функциональное программирование появилось не вчера. Но оно так и не приобрело какой-либо дикой популярности, и, вероятно, не просто так.

И

Для начала давайте создадим класс

https://github.com/Lambdish/phunctional

https://github.com/lstrojny/functional-php

2 пакета, которые дают функциональные примитивы в php, но более правильно без самопала7

Сама тема имхо хороша, но пример какой-то вымученный и не показывает преимущества в таком подходе

Не очень понял, при чем тут symfony. Для примера?

В пхп каждая новая фича, которая была уже придумана, звучит как новая технология.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий