)<?php
class SinglePlaceholder
{
}
class VariadicPlaceholder
{
}
$PLACEHOLDER = new SinglePlaceholder();
$VARIADIC_PLACEHOLDER = new VariadicPlaceholder();
function partial(callable $in, ...$args) {
$fmap = [];
$partialIndex = 0;
$variadic = false;
foreach ($args as $k => $arg) {
if ($arg instanceof SinglePlaceholder) {
$fmap[$partialIndex++] = $k;
}
if ($arg instanceof VariadicPlaceholder) {
$variadic = true;
if ($k < count($args) - 1) {
throw new ArgumentCountError('Only the last parameter may be a variadic placeholder');
}
$fmap[$partialIndex++] = $k;
}
}
return static function (...$partialArgs) use ($in, $args, $fmap, $variadic) {
if (count($partialArgs) < count($fmap)) {
throw new ArgumentCountError('Expected ' . count($fmap) . ' only received ' . count($partialArgs));
}
foreach ($partialArgs as $pIndex => $pValue) {
$targetSlot = $fmap[$pIndex] ?? null;
if ($targetSlot === null) {
if ($variadic) {
$args[] = $pValue;
}
else {
throw new ArgumentCountError('Too many arguments without a variadic placeholder');
}
}
else {
$args[$targetSlot] = $pValue;
}
}
return $in(...$args);
};
}
function foo($a, $b, $c, $d, $e) {
var_dump($a, $b, $c, $d, $e);
}
print_r(partial('foo', 1, $PLACEHOLDER, 3, $PLACEHOLDER, 5)(2, 4));
print_r(partial('foo', $VARIADIC_PLACEHOLDER)('a', 'b', 'c', 'd', 'e'));
print_r(partial('foo', 1, 2, 3, 4, 5)());
preferences:
26.46 ms | 402 KiB | 5 Q