bind
Помните, я недавно рассказывал, почему не стоит пренебрегать функциями в PHP? В этом посте приведу ещё один пример функции, выполняющей роль фасада.
Иногда в инфраструктурном коде приходится обходить инкапсуляцию. Например, когда пишешь свой DataMapper или оборачиваешь корявое вендорное API.
Самый простой способ получить доступ к чему-то приватному — это привязать замыкание к контексту класса при помощи Closure::bind (подробнее в статье Ocramius). Однако у сигнатуры этого метода есть ряд проблем:
1. По опыту удобнее всего менять
2. Можно было бы скипнуть второй параметр, используя именованные аргументы, но
3. Метод возвращает
4. Не поддерживается статанализ (лечится добавлением соответствуюещго стаба в проект или в анализаторы через PR).
Что будем делать? Мучиться? Нет, добавим в проект простую функцию
Вариант такой функции: https://3v4l.org/K1LUG.
Кстати, Psalm падает при использовании
И ещё. Я считаю, не стоит делать composer-пакеты из таких функций, потому что в каждом проекте они будут называться и выглядеть по-разному. Такие тривиальные штуки гораздо проще копировать и адаптировать под свои представления о прекрасном, чем тянуть сомнительные зависимости.
Помните, я недавно рассказывал, почему не стоит пренебрегать функциями в PHP? В этом посте приведу ещё один пример функции, выполняющей роль фасада.
Иногда в инфраструктурном коде приходится обходить инкапсуляцию. Например, когда пишешь свой DataMapper или оборачиваешь корявое вендорное API.
Самый простой способ получить доступ к чему-то приватному — это привязать замыкание к контексту класса при помощи Closure::bind (подробнее в статье Ocramius). Однако у сигнатуры этого метода есть ряд проблем:
1. По опыту удобнее всего менять
scope
, а не $this
, но параметр $newScope
идёт третьим.2. Можно было бы скипнуть второй параметр, используя именованные аргументы, но
$newThis
не имеет значения по умолчанию, поэтому приходится явно передавать null
.3. Метод возвращает
?Closure
, из-за чего приходится проверять !== null
вместо того, чтобы сразу писать Closure::bind(fn () => ...)()
.4. Не поддерживается статанализ (лечится добавлением соответствуюещго стаба в проект или в анализаторы через PR).
Что будем делать? Мучиться? Нет, добавим в проект простую функцию
bind
, которая разом решит все проблемы!Вариант такой функции: https://3v4l.org/K1LUG.
Кстати, Psalm падает при использовании
@template of Closure
, а вот PhpStan справляется: https://phpstan.org/r/40205124-4b2f-4c1b-94fe-a05eb14488e2.И ещё. Я считаю, не стоит делать composer-пакеты из таких функций, потому что в каждом проекте они будут называться и выглядеть по-разному. Такие тривиальные штуки гораздо проще копировать и адаптировать под свои представления о прекрасном, чем тянуть сомнительные зависимости.