Комментарии 62
Большое спасибо за дайджест)
Сообщество также проголосовало за использование префиксного синтаксиса sodium_* вместо пространства имен \Sodium\*. Тем не менее уже доступна обертка firehed/sodium для использования функций через пространство имен.
Кому-то жить не хочется, если он не ощущает себя важной жопой пишущим качественный ООП-код?)
Кому-то жить не хочется, если он не ощущает себя важной жопой пишущим качественный ООП-код?)Тебе просто неприятно то, что кому-то хочется иметь неймспейсы? Это плохо? Плохо выделяться из толпы или плохо быть толпой? Зачем вообще выдавать свою качественую характеристику предпочтений манеры работы других людей? Почему ты вообще это написал? Зачем ты заставил меня задавать все эти вопросы?
Очень много всяких вещей в программировании программисты делают без реального обоснования с точки зрения пользы для программного кода.
Найс фингс — это ложить все функции в свои неймспейсы? Может вообще удалить функции и оставить только их ооп-вариации? Чтобы совсем как у взрослых было?
И чем лучше от этого станет код? Тем что объектов станет больше? Тем что use-директив в начале файла добавится?
Удивительно, как часто программисты любят называть "клевыми штуками" пустые с рациональной точки зрения вещи.
Глобальные функции просты и очень удобны в использовании. Я очень рад, что они есть в php, и сам часто расширяю код проекта своими собственными функциями. Выглядит красиво, работается удобно, понимается легко. Разве не к этому надо стремиться при написании большого проекта?
И чем лучше от этого станет код? Тем что объектов станет больше? Тем что use-директив в начале файла добавится?
Мне нравится идея. что в начале файла есть эдакие "импорты" других модулей, и можно быстро увидеть зависимости кода. Позволяют за несколько секунд понять насколько все хорошо или плохо.
Глобальные функции просты и очень удобны в использовании.
нэймспейсы лишь позволяют прибраться в глобальной области видимости, функции как были глобально доступными так и остаются. Не понимаю почему вы так завелись.
Выглядит красиво, работается удобно, понимается легко. Разве не к этому надо стремиться при написании большого проекта?
выглядит некрасиво. работается удобно до какого-то момента, в целом же в вашем коде просто увеличивается количество шума. И если проект большой, то это будет сильно влиять на читаемость кода, и как следствие, поддерживать такой код будет чуть-чуть да дороже.
У нас довольно большой проект, разбитый на модули. Даже в этом случае я пока не вижу необходимости раскладывать функции каждого модуля в свой неймспейс. Хотя возможно в будущем будет смысл, да. Так как мы и префиксы для названий функций не используем.
Приведу несколько примеров кода нашего проекта. Скажем, есть у нас модель текстовых данных одного объекта. И вот там есть вот такой метод:
public function setDescriptionMarkdownAttribute($value)
{
$this->attributes['description_markdown'] = $value;
$this->attributes['description_html'] = ace_editor_parse($value);
}
Как видим, здесь вызывается функция. Она парсит строку и возвращает нужный HTML код. Разве не просто и красиво?
Или вот ещё пример, метод класса лекции в нашем проекте:
public function getFirstContentLink(Course $course)
{
return link_to_lesson($course, $this, $this->realContents->first());
}
Как видим, тут используется функция link_to_lesson. Она генерирует ссылку на блок контента лекции определённого курса. Эта функция используется в том числе в шаблонах проекта, а также в прочих PHP классах, например в генераторе карт сайтов… В общем, одна функция — используется везде, где нужно. Разве не удобно?
Или вот ещё один очень простой хелпер в модели пользователя, тут вообще всё просто:
/**
* Возвращает True в том случае, если данная модель является текущим
* авторизованным пользователем.
*
* @return bool
*/
public function isCurrentUser()
{
return ($this->id === current_user()->id);
}
Ну и напоследок — метод в классе авторизации для создания нового пользователя для проекта, который тоже использует по большей части функции:
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
event(new UserCreated($user));
send_email_to_admins('У нас новый пользователь!', 'emails.user-registered', [
'newUser' => $user,
]);
// Отправим пользователю сообщение-приветствие
send_email_to_user('welcome', $user);
session(['first-login' => true]);
return $user;
}
Я не имею права показать и доказать свою точку зрения на практических примерах из своего реального проекта?
Вам код ревью сделать и описать проблемы?
Да я вроде и сам вполне нормально могу работать с проектами. И сам занимаюсь код ревью. Проблемы, что тут вы пишете — они больше из пальца высосаны, и реальной проблемы не составляют. Я это уже обсуждал в своей отдельной статье на хабре с людьми. Да, если есть желание — можете подключаться к тем обсуждениям. Только пожалуйста прочитайте сначала мои разъяснения, чтобы не проходиться повторно по одним и тем же темам.
Проблемы, что тут вы пишете — они больше из пальца высосаны
Если вы не пишите тестов — то да, согласен. В целом это все проблемы людей которые не хотят тратить деньги на ручное тестирование.
p.s. Если что меня не напрягают функции как таковые, меня напрягают event
, current_user
и send_email_to_user
. К примеру у меня нотификации отправляются так:
$this->notificator(new WelcomeNotification($user));
Профит — легко тестировать, легко поддерживать, разделение ответственности, нет волшебных строковых констант в коде, легко рефакторить, большая часть тупых багов выявляется статическим анализом.
На самом деле тестируется все это без проблем, и мы пишем тесты в проекте, правда на столь активно.
И пара функций здесь вообще из ларавел взяты, они есть из коробки: event и session. Ларавел тоже вроде покрыт тестами.
Тупые баги тоже вроде находятся без проблем) я только не понял что за статический анализатор.
Узнаю laravel. Там много всяких штуковин, вроде event
, session
, Auth::user()
, DB::table('smth')->insert()
. Снаружи выглядит весьма сурово, но это всё фасады на магии __callStatic. Внутри работает service locator и dependency injection (если есть желание — можно использовать только DI, без магических геттеров).
event:
https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/helpers.php#L477
app:
https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/helpers.php#L99
Нотификации, путь слабых:
function actionRegister()
{
....
event(new UserRegisteredEvent($user));
}
Нотификации, ваш путь (здесь могу ошибиться с выбором внедряемого класса, только начинаю осваивать laravel):
function actionRegister(Illuminate\Contracts\Events\Dispatcher $eventService)
{
...
$eventService->dispatch(new UserRegisteredEvent($user));
}
P.S.: ура, markdown разметка для отхабренных! :)
собственно вы и показали что используете префиксы: ace_editor_
, send_email_
Это не префиксы :) Префиксы тогда должны быть например так: strings_ace_editor_parse
. То есть, функция из ядра проекта, отвечающая за работу со строками.
Или education_link_to_lesson
. То есть, функция из модуля интерактивных уроков.
Но лучше тут конечно неймспейсы наверное сделать всё-таки, если что-то делать. Просто красивее выйдет в итоге для нашего проекта, как мне кажется. А что насчёт ядра PHP — то там как-то они всё равно очень логично всё делают, даже без неймспейсов.
Префиксы тогда должны быть например так
вообще-то нет. У вас префикс — ace_editor
— определяет к какому модулю они принадлежат.
Но лучше тут конечно неймспейсы наверное сделать всё-таки, если что-то делать.
Да, выйдет что-то типа
use function {aceEditor\parse};
// ...
parse($str);
Всё-таки не так на самом деле. Для этого ейс эдитора всего одна функция в проекте. И она лежит среди других функций для работы со строками.
Поэтому я и говорил о том, что в нашем проекте если неймспейсы делать функциям, то можно сделать например… вот так, чтоли:
namespace App\Functions\Strings;
function ace_editor_parse() {
//...
}
Но в данный момент я лично не ощущаю в этом нужды. И так всё вполне красиво и удобно.
Вот вы в своем коде указали что используете функцию bcrypt
. Вместо нее стоило бы использовать абстракцию — password_hash
. Заметте то обе эти функции не будут лежать в нэймспейсе string
так как то что они используют строки в качестве значений, это не основная цель. Точно так же и ваш ace_editor_parse
— его задача не просто со строками работать, а парсить с какой-то целью (скорее всего что-то связанное с ace_editor). Ну и исходя из этого и надо дробить на модули.
Вместо нее стоило бы использовать абстракцию — password_hash
Это хелпер Laravel, идущий из коробки. Я его использую просто потому что во фреймворке это считается правильным кодом. Можно конечно и об абстракции было подумать.
С остальным согласен, оно немного не до конца хорошо раскидано) но опять же. Работе сильно не мешает. Как-нибудь может немного наведу там порядок просто, раскидаю функции по более корректным папкам)
эх… ох уж этот глобальный доступ к зависимостям...
Я не очень люблю критиковать чужой код, да и Вам вряд ли это понравится, но раз уж Вы его выложили, то, думаю, имею право высказаться.
public function isCurrentUser()
{
return ($this->id === current_user()->id);
}
Если я вижу такое у кого-то из коллег, то требую переписать.
У вас current_user() как определяется? Я полагаю, берётся из сессии, кук, заголовка — это всё накроется медным тазом, когда захочется вызвать данный код из консоли.
Почему данные HTTP-запроса (или хз вообще какого запроса — тут не ясно) протекают в модель, которая вообще не должна быть привязана ни к какому интерфейсу взаимодействия с приложением? И как это тестировать?
event(new UserCreated($user));
send_email_to_admins('У нас новый пользователь!', 'emails.user-registered', [
'newUser' => $user,
]);
// Отправим пользователю сообщение-приветствие
send_email_to_user('welcome', $user);
session(['first-login' => true]);
Тут я вообще не понял, такое ощущение, что прикрутили события после того как сделали отправку писем, но забыли сделать рефакторинг. Если у вас идёт вызов двух функций, от которых тем более не требуется ответ, почему нельзя их же обработать через этот event?
И останется только:
event(new UserCreated($user));
И я ничего не говорю про то, что ваш код абсолютно не модулен и попытка использовать его без изменений вне рамок первоначального плана практически невозможна, как и тестирование. Это лапша.
Ну что вы сразу обидными словами кидаетесь) Всё прекрасно тестируется, не стоит торопиться с выводами.
У вас current_user() как определяется? Я полагаю, берётся из сессии, кук, заголовка — это всё накроется медным тазом, когда захочется вызвать данный код из консоли.
Не накроется, не беспокойтесь. Функция current_user()
— это просто удобная обёртка над основным синглтон-классом авторизации Laravel:
use App\Models\User;
function current_user()
{
$current_user = Auth::user();
if ($current_user === null) {
$current_user = new User();
}
return $current_user;
}
Класс Auth
, в котором вызывается статический метод, тоже без всяких проблем тестируется: потому что это фасад Laravel, и он тоже идёт из коробки во фреймворке.
В тестах у нас пишется вот такой код:
/**
* Убедимся, что система даёт доступ на вход в админку
* пользователю-админу
*/
public function testAdminGrantAccess()
{
$adminUser = create_user('admin');
$this
->actingAs($adminUser)
->visit(route('admin'))
->see(__('admin.panel'))
;
}
$this->actingAs($user)
— стандартная функция из набора инструментов Laravel для тестирования проекта. Ну и да… оно вызывается из консоли.
Тут я вообще не понял, такое ощущение, что прикрутили события после того как сделали отправку писем, но забыли сделать рефакторинг
Я не особо согласен с этим. Не обязательно ведь теперь засовывать в реакцию на эвент вообще всю логику создания пользователя. Просто есть основные действия при создании пользователя, которые являются ядром проекта, и есть некоторые дополнительные, которые выполняются модулями проекта. Поэтому для модулей и был сделан эвент.
Вы правда не видите проблем в том, что модель напрямую обращается к параметрам запроса?
Чтобы я увидел реальную проблему, опишите пожалуйста ситуацию, когда это будет мешать нормальной работе проекта. Только не какие-то абстрактные идеи и предположения, пожалуйста. Какой-то конкретный юз-кейс.
Потому что это вот и есть основная проблема многих программистов: они берут какую-то теоретическую некорректность и начинают учить других писать код, основываясь на неё. В общем-то, изначально я про это и писал, в самом первом своём комментарии к этому посту.
Проблема в том, что с одной и той же моделью можно работать разными способами — запросы будут разные.
Сейчас она обращается к сессии.
Потом понадобилось сделать консольную команду (не тест), чтобы сделать что-нибудь с пользователями. Как в данном случае будет работать Auth::user()? Как сделать пользователя авторизованным?
Проблема в том, что с одной и той же моделью можно работать разными способами — запросы будут разные.
Не понял проблему. Опишите пожалуйста более конкретную ситуацию.
Сейчас она обращается к сессии
Да не к сессии эта функция обращается) А к синглтон-сервису в ларавел фреймворке, я ведь написал)
Указать, какой пользователь в данный момент авторизован — очень просто. Вам поможет любой из методов, описанных в официальной документации к Laravel.
Соответственно, сервис будет возвращать того пользователя, которого вы указали в качестве авторизованного.
Синглтон сервис в ларавеле по умолчанию обращается к сессии.
Если сервис зависит от абстрактной сессии (в данный момент это просто HTTP-сессия), то модель, зависящая от этого сервиса зависит и от сессии.
Так что именно к сессии она и обращается (хоть и не напрямую).
И да, можно сделать так
Auth::login($user);
// и совсем в другой части проекта
$u->isCurrentUser();
И всё это будет работать. Но это будет понятно только тому, кто изначально писал этот код.
Всё-таки, снова слона из мухи раздуваете.
Я честно не вижу здесь чего-то сложного и плохого. Стандартный сервис авторизации вы можете расширить своим собственным классом и реализовать там такую логику, какая будет нужна лично вам. Этим и прекрасна архитектура Laravel: при наличии нормальных мозгов, вы можете без особых проблем переписать и расширить логику работы фреймворка.
Сервис авторизации стандартный, но использование его нестандартное.
Есть объект $user.
Человек видит в нём метод isCurrentUser. Без копания в коде (а в идеале нужно смотреть только на сигнатуру метода) не понятно как заставить его работать, и будет ли он работать вообще без дополнительных манипуляций.
Что делать разработчику?
- Будет ли метод работать сразу, потому как мы обрабатываем http-запрос?
- Нужно ли вызывать Auth::login снаружи, т.к. http-запрос отсутствует?
- Нужно ли делать ещё что-то?
Всё это неясно. Именно в этом проблема таких неявных и при этом жёстких зависимостей.
Объект должен быть максимально самодостаточным и его зависимости должны быть явными. Если этого нет — его просто неудобно использовать.
Ну у вас опять начинается теоретика. Я ведь просил без неё.
В ларавел не зря есть понятие сервис-провайдеров, а также двух этапов их инициализации: регистрация и загрузка.
Уже после этого будет запущен различный код вашего приложения. Будь то консольная команда, будь то ваше API, или же самый обычный GET-запрос на вебсайт.
Если вы будете отталкиваться от архитектуры фреймворка, у вас не будет возникать этих вопросов, которые вы сейчас задаёте. Да, надо знать немного больше. Да, это выходит за рамки каких-то типичных абстрактных Единственно Истинных правил написания ПО. Если для вас критично им следовать — то я могу только сказать, что это просто ошибочное мышление.
Как пишет Стивен Макконнел в своей книге "Совершенный Код":
Как сказал Ф. Дж. Плоджер, «чем догматичнее вы будете в отношении методики проектирования, тем меньше реальных проблем решите» (Plauger, 1993). Рассматривайте проектирование как грязный, неряшливый эвристический процесс. Не останавливайтесь на первом проекте, который пришел вам в голову. Сотрудничайте. Стремитесь к простоте. Создавайте прототипы, если нужно. Не забывайте про итерацию. Вы будете довольны своими проектами.
Очень хороший абзац, на мой взгляд. Поразмышляйте над ним, особенно над первым предложением в нём.
Какая уж тут теоретика?
Конкретный случай. Разработчику нужно вызвать код
$user->isCurrentUser()
Он знает, что этот метод корректно работает в контроллере.
Но сейчас ему нужно вызвать этот код в консоли, а завтра в контексте API-контроллера.
Будет ли это работать без предварительных приготовлений где-то в сервис-провайдере? Нет.
Знает ли об этом разработчик? Нет. Всё что у него есть — это метод, который каким-то образом (видимо, по контексту вызова) определяет, авторизован пользователь, или нет. Как он определяет — разработчик не знает. Он и не должен знать — инкапсуляция.
К вопросу о простоте, он мог бы вызвать:
Auth::user() && Auth::user()->id == $user->id
и он знал бы, что обращается к сервису авторизации, который может быть как-то сконфигурирован как угодно.
Он мог бы сделать ещё проще, в случае, если ему приходит токен в заголовке и работа с сессией не нужна.
$headerUserToken == $user->token
Но у него есть этот волшебный метод isCurrentUser, который скрывает всю информацию об использовании сервиса.
- Использует ли он какие-то сервисы — разработчик не знает.
- Будет ли работать он, если пользователю пришёл HTTP-заголовок secret_user_token — он не знает.
- Будет ли работать он, если второй и третий аргументы командной строки являются логином и паролем — он не знает.
Он и не должен ничего этого знать.
Почему Вы всё время пытаетесь рассказать как работают сервис-провайдеры в ларавеле? Мои претензии не к ним, а непосредственно к модели User.
Потому что вполне нормально, что авторизация может работать на уровне сервис провайдеров или middleware. Поэтому я вам и указываю на них.
Абсолютно нормально, что один уровень приложения зависит от другого уровня приложения. И ведь точно также, указанный вами код Auth::user() && Auth::user()->id == $user->id
будет зависеть от всего, что вы перечислили.
Если вы это не хотите признавать, почему это должно быть моей проблемой? Я же просто добавил удобный метод для модели пользователя.
Конечно нормально. В приложении всегда один уровень зависит от другого.
В тему цитат приведу первые 4 строчки философии python:
- Красивое лучше, чем уродливое.
- Явное лучше, чем неявное.
- Простое лучше, чем сложное.
- Сложное лучше, чем запутанное.
Метод isCurrentUser неявный и запутанный.
Неявный потому как данные зависимости, простите за тавтологию, не являются явными.
Запутанный из-за того, что зависимость кольцевая: модель пользователя (модель бизнес-логики) зависит, от сервиса более высокого уровня (который её и использует).
Оно вполне явное и вполне простое. Вот вы реально нашли такую мелочь и пытаетесь из неё хоть что-то вывести.
Давайте заниматься полезными делами, за все сообщения спасибо, но я с вами всё равно не согласен. Любые правила полезны до тех пор, пока мы не стремимся довести их до фанатичного применения во всех ситуациях. До свидания.
Т.е. вы предлагаете везде копипастить код ?
Auth::user() && Auth::user()->id == $user->id
Ну это тоже не дело.
Явное лучше, чем неявное
Но повторение кода тоже зло. Именно из-за этого есть "магия" которая позволяет убрать копипаст. Так что тут нужен баланс и компромисс.
Абсолютно нормально, что один уровень приложения зависит от другого уровня
Нормально — это когда у нас нижние уровни не зависят от верхних. У вас же штуки из верхних уровней тянутся вниз.
Если вы это не хотите признавать, почему это должно быть моей проблемой?
я в своем коде в модулях нижних уровнях просто передаю юзера если надо. Они не лазают за ними сами. Это и удобнее, и читается проще, и с точки зрения масштабирования логики норм. И самое интересное — это не дольше по времени. То есть минусов вообще никаких. Ну и в Laravel5.3+ нормальный IoC есть что бы не страдать чушью из 4-ой.
Ну и в Laravel5.3+ нормальный IoC есть что бы не страдать чушью из 4-ой
Можете привести какие-то конкретные примеры, чего "нормального" появилось в сервис контейнере в ларавел 5.3+?
Ну и я снова не сильно согласен в целом. Опять до фанатизма доходите, извините. Пусть в одном месте проекта у нас вытаскивается модель текущего пользователя. Текущий пользователь — он на то и текущий. Он один. Его даже менять не нужно в 99% ситуаций жизни проекта, но даже если поменяешь в основном синглтон классе авторизации — то в других местах приложения всё отработает как полагается. Да, это чуть чуть менее явно, также как с эвентами, про которые я вам уже говорил в другом комментарии. Но я не могу назвать это полностью плохим подходом, который не имеет права на жизнь. Иначе и эвенты бы тоже надо было закидать камнями, но почему-то этого ведь никто не делает?
Но я не могу назвать это полностью плохим подходом, который не имеет права на жизнь.
Так как бы я этого и не говорю. Для маленьких/средних проектов с учетом нормальных сервис-локаторов ларавели жить можно.
Иначе и эвенты бы тоже надо было закидать камнями
Тут опять же. Ивенты нужны дабы снизить связанность. Например у меня есть модуль каталога товаров, и по изменению товара я должен сообщить всем заинтересованным модулям что я что-то поменял. Например модуль поиска, который должен синхронизировать данные в другой базе данных (эластике например). В этом случае у меня модуль поиска зависит от модуля каталога, но модуль каталога ничего не знает о модуле поиска.
Другой вопрос что просто так их выкидывать когда еще данные небыли записаны в базу так себе идея. Потому я использую доменные ивенты для этого (они сначала собираются а потом, после коммита транзакции, файрятся). Ну и в целом в пределах одного модуля использование ивентов уже не оправдано. Или же если у нас нет проблемы циклических зависимостей модулей, лучше явно что-то дернуть.
Словом, все относительно. Нет абсолютных правил. Но есть лучшие практики которым стоит придерживаться.
Не знаю за ларавель, но в симфони евенты, как и все остальное, полностью DIC-based, это значит что можно найти все зарегистрированные листнеры (либо посмотреть в рантайме, если вы подписываетесь в рантайме).
Синглтоны и статические фасады же позволяют вам обращаться, в том числе к мутирующим сервисам из любого места, что обычно при недостатке контроля или компетенции приводит к лапше в коде.
Я в целом согласен с Fesor, однако уточню, что в целом можно писать какой угодно код, если он никогда не будет никому показан. В противном случае лучше пользоваться вот теми самыми принципами из питона выше.
Помимо классических HTTP-страниц и консоли, Ваше приложение может выступать в роли API-сервера, а там вообще довольно часто авторизация определяется токеном, который клиент отправляет в заголовках запроса — без всяких сессий.
пишущим качественный ООП-код?)
нэймспейсы не имеют никакого отношения к ООП. Это просто способ сделать более удобное API, без префиксов. Там внутри просто функции.
удивляет нежелание его принимать. Последнее время ананимок в коде очень много. И код бы стал гораздо приятнее.
Сейчас напоролись на то что ключевое слово fn
не хотят вводить (есть же function
уже). Ну и в целом будет нарушение обратной совместимости. Потому обсуждается альтернативый вариант синтаксиса:
$fn = |$x| => $x * 2;
array_reduce($arr, |$str, $chunk| => $str . $chunk, '');
по мне так fn
выглядит самым приятным и логичным из 4 вариантов (5 если считать еще и |
). Как раз сокращенное function
.
мдя… чем, интересно, широкоиспользуемый () => $x * 2;
не нравится? (парсер же вроде нормальный уже?)
(парсер же вроде нормальный уже?)
Да, нормальный LR(1) парсер. Что значит единичка? Это означает что дальше чем на одину лексему вперед вам видеть не дают. То есть вы должны понимать является ли выражение лямбдой либо с самого первого токена либо на один токен вперед.
С выражениями типа $x => $x * 2
проблема заключается в том, что =>
используется в разных контекстах и с такой записью невозможно точно определить что это за выражение не разобрав его до конца. Ну и в целом остаются конфликты с yield $key => $value
. Потому без ключевого слова или специального символа в начале лямбды не обойтись.
Если что в python например ввели ключевое слово lambda
, в ruby у нас примерно такой же вариант как предлагают в php: |x| => x * 2
ну и т.д.
И вы, кажется, даже в слове «анонимок» не сделали ошибки в контексте данного случая...)
вы видимо просто не представляете насколько это удобно.
И дело не в том, что писать на сколько-то символов больше (автокомплит IDE нивелирует), а в том, что текущий синтаксис сильно «шумит» – у меня бывает, что «накладные символы» по длине такие же как полезное действие в функции, – такое сложно распарсить глазами и понять.
Да и IDE обычно фолдит такие вещи – приходится кликать в однострочники чтобы посмотреть что они делают что-то похожее на array_column, только для объектов или считают среднее арифметическое по аттрибуту из коллекции. С коротким синтаксисом это распознаётся глазом гораздо быстрее. По крайней мере, лично моим – точно быстрее.
Вон, JS со стрелочными функциями последнее время всё больше на brainfuck похоже становится.
новый будет сливаться.
как напишите так и будет. Не спроста в текущих RFC не предлагается поддержки нескольких выражений на лямбду. Это слегка противоречит идее "функциональных выражений". Так что сливать не должно.
JS со стрелочными функциями последнее время всё больше на brainfuck похоже становится.
Да нет, как раз таки все хорошо. Бывает что разработчики злоупотребляют но… в среднем выходит читаемо.
пока не ввели какой-то синтаксис для лямбд и вы работаете в продуктах Jetbrains можно этим пользоваться: https://github.com/vkurdin/idea-php-lambda-folding
hannob/php-crashers — Примеры скриптов, которые вызывают segfault в PHP
Неверно, там всё таки примеры не с segfault в классическом его понимании, а банальная бесконечная рекурсия, таких примеров можно миллион сделать.
PHP-Дайджест № 102 – интересные новости, материалы и инструменты (1 – 12 февраля 2017)