Skip to content

Instantly share code, notes, and snippets.

@kmuenkel
Last active November 4, 2021 16:49
Show Gist options
  • Save kmuenkel/f14310ca98258d6623fc1f5fc767ff78 to your computer and use it in GitHub Desktop.
Save kmuenkel/f14310ca98258d6623fc1f5fc767ff78 to your computer and use it in GitHub Desktop.
Allow for consistent syntax when including an array of parameters in Laravel's app() helper function when the concrete binding is a Closure.
<?php
if (!function_exists('function_binding')) {
/**
* @param callable $callback
* @return callable
*/
function function_binding(callable $callback): callable
{
$params = app(ReflectionFunction::class, ['name' => $callback])->getParameters();
/** @var ?ReflectionParameter $firstArg */
$firstArg = array_shift($params);
$firstArgType = $firstArg ? (string)$firstArg->getType() : null;
$firstArgName = $firstArg ? $firstArg->getName() : null;
$expectsContainer = is_subclass_of($firstArgType, Container::class) || !$firstArgType && $firstArgName == 'app';
!$expectsContainer && $firstArg && array_unshift($params, $firstArg);
$params = array_map(function (ReflectionParameter $parameter) {
return $parameter->getName();
}, $params);
return function (Container $app, $args = [], ...$additionalArgs) use ($callback, $params, $expectsContainer) {
$args = !is_array($args) || !empty($additionalArgs) ? array_merge((array)$args, $additionalArgs) : $args;
if ($numArgs = count($args)) {
$expectedArgKeys = array_slice($params, 0, $numArgs, true);
$numExpected = count($params);
$noMore = array_slice($args, 0, $numExpected, true);
$noLess = array_pad($noMore, $numExpected, []);
$namedArgs = array_is_numeric($noLess) ? array_combine($expectedArgKeys, $noLess) : $noLess;
$keyOrder = array_flip($expectedArgKeys);
$args = array_merge($keyOrder, $namedArgs);
}
$expectsContainer && array_unshift($args, $app);
return $callback(...array_values($args));
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment