Процесс, который вы хотите называется "функции высшего порядка"
// функция "высшего" порядка - что в ней высшего - надо спросить у того кто придумал, высший человек наверное
$fnPow = function ($x, $y) {
return pow($x, $y);
};
$fnPowExtended = function () use ($fnPow, $b, $c) {
var_dump($b);
var_dump($c);
return $fnPow($b, $c);
};
$fnPowExtended(2, 3);
// 2
// 3
// 8
Таким образом чтобы прокинуть что-то в уже созданную функцию вам нужно создать новую функцию и прокинуть туда существующую и что-то ещё. Более того, вы можете прокинуть функцию саму в себя, чтобы сделать рекурсию.
$fnRecursion = function () use (&$fnRecursion) {
$fnRecursion(); // infinite recursion here
}
Я полагаю что ваш интерес вызван желанием создать функцию bind()/call()/apply(), как в javascript. В ПХП этим путем не пошли, т.к. ООП все же хоть и дороже в разработке, но понижает порог входа новых людей в проект. Решение спорное, т.к. в ООП надо уметь, а функционалка может быть лишь бы было. И понимая что "старый код не трогать, а заменять" это вроде не так уж плохо. Но в пхп часто старый код именно трогают, доделывают, подпиливают. Функционалка усложняет процесс понимания "что происходит", поэтому ей редко пользуются. К тому же в пхп до недавнего времени вообще короткой записи не было, и писать function () use () {}, и потом переживать, что там чото с памятью может быть и пересылом часто сложнее, чем нажать CTRL+N в IDE и создать новый класс.
bind() должна бы выглядеть примерно так в PHP (но ей здесь никто не будет пользоваться):
/**
* bind
* копирует тело функции и присваивает аргументы на их места в переданном порядке
* bind('is_array', [], 1, 2) -> Closure of (function is_array($var = []))
*
* @param null|object $newthis
* @param callable $func
* @param mixed ...$arguments
*
* @return \Closure
*/
public function bind(?object $newthis, callable $func, ...$arguments) : \Closure
{
if (! is_string($func)) {
$bind = $arguments;
} else {
// string
$bind = [];
$rf = new \ReflectionFunction($func);
$requiredCnt = $rf->getNumberOfRequiredParameters();
while ( $requiredCnt-- ) {
$bind[] = null !== key($arguments)
? current($arguments)
: null;
next($arguments);
}
$func = \Closure::fromCallable($func);
}
if (null !== $newthis) {
if (! $func instanceof \Closure) {
$func = \Closure::fromCallable($func); // throws exception if not possible
}
$func->bindTo($newthis); // throws exception if not possible
}
$result = static function (...$args) use ($func, $bind) {
$bind = array_replace(
$bind,
array_slice($args, 0, count($bind))
);
return call_user_func_array($func, $bind);
};
return $result;
}
Почему она такая "странная"? Потому в php есть еще одна проблема. Созданные функции (не безымянные, вот только не помню - кажется только встроенные, свои - не такие строгие) требуют строгое число аргументов на своих местах. Если вы передадите больше или меньше - они ломаются и не работают. Рефлексия считывает "а скока надо" и передает ровно столько, на остальное забивает.
===
В ООП для подобных вещей используют декорирование (decoration) (не путать с кАррирование (currying)). Вы пишете класс, который на вход ожидает обьект другого класса, чтобы нарастить его функционал, не влазя в детали.
Чуть позже в python поняли, что можно не только готовые объекты заворачивать, но и декорировать любую функцию уже на этапе описания. На псевдокоде это выглядит так:
[send_telegram] // use result to call new function
[send_email] // use result to call new function
[push_event] // use result to call new function
function register() {
// do some
}
В среде разработчиков ООП этот процесс не нашел большого распространения (как бы Симфони не старался продвигать написание кода и валидаций в аттрибутах и аннотациях - это все равно чертова магия, которая требует высокого порога входа и даже специальной теории баз данных, которую не понимает никто кроме программистов - что создает барьер между бизнес-аналитиками, даже теми, кому выставляли порог входа - знание SQL, так и барьер между опытными разработчиками, которые привыкли прослеживать ход программы, а им пытаются навязать изучение какой-то штуки, которая читает приписки и делает что-то описанное черти-где).
Причина процесса - вы все равно переписывается старые файлы. ООП и принцип солида отталкивается от того, что старый модуль вынимается и выбрасывается, а не дорабатывается, т.к. вызовет новые баги.
1) Я стараюсь не увлекаться функциями, потому что у них проблемы с "сериализацией" - сохранить их в файл или передать по сети проблематично. Вы буквально передадите номер строки в коде, который завтра может быть другой и вторая сторона должна иметь точно такой же код, это ненадежно.
2) Функции работают с памятью несколько по особенному. То есть если не писать перед функцией слово `static`, что означает "не хранить внутри $this того места где её создали", можно получить интересную картинку если эту функцию вызовут в рекурсии. Оригинальный класс, который для неё $this, накопив данные и начав копировать эту функцию в момент того как вы пишете $a = function () {}, будет каждому экземпляру копировать данные этого объекта. И случайно в коде выполнив циклом 300 раз $a = function () {} вы 300 раз скопируете данные, которые возможно представляли собой "много текста" и ушатаете память.
С функциями нужно быть осторожным. Чем реже, тем лучше. Но это не значит что они плохие. Так например прослушку постоянного процесса в скрипте, который никогда не завершится с возможностью подключать свои действия сильно проще написать на функциях-обработчиках. Хотя ООП рекомендовал бы использовать имена классов и фабрику их создающую, гарантируя что конфиг будет содержать текст а не объекты.
Не уверен, что понимаю как работает ядро яваскрипт, но что-то мне посказывает, что там есть общий скоуп и ничего никуда не копируется, а просто берется то что есть либо везде, либо конкретно здесь, т.к. передали. В пхп у каждой функции свой скоуп. С одной стороны это обрезает руки, с другой стороны не позволяет совершить глупых ошибок по типу "вывести то, чего тут может и не быть".