bind



Помните, я недавно рассказывал, почему не стоит пренебрегать функциями в 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-пакеты из таких функций, потому что в каждом проекте они будут называться и выглядеть по-разному. Такие тривиальные штуки гораздо проще копировать и адаптировать под свои представления о прекрасном, чем тянуть сомнительные зависимости.