drop extra arguments for compiled internal functions
This commit is contained in:
parent
1e94adc872
commit
bdb49b0d78
@ -66,17 +66,26 @@ class PartiallyAppliedFunction implements Decorator, Compilable
|
||||
return $this->callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal functions throw when given too many arguments, so for a non-variadic internal target the compiled
|
||||
* closure drops trailing arguments past its parameter count (e.g. the key passed by collection functions).
|
||||
*/
|
||||
public function compile(): \Closure
|
||||
{
|
||||
$callable = compile($this->callable);
|
||||
$arguments = $this->arguments;
|
||||
$placeholders = array_keys($arguments, PLACEHOLDER, true);
|
||||
|
||||
$target = new \ReflectionFunction($callable);
|
||||
$extra = $target->isInternal() && !$target->isVariadic()
|
||||
? max(0, $target->getNumberOfParameters() - count($arguments))
|
||||
: null;
|
||||
|
||||
if (empty($placeholders)) {
|
||||
return static fn (...$args) => $callable(...$arguments, ...array_values($args));
|
||||
return static fn (...$args) => $callable(...$arguments, ...array_slice(array_values($args), 0, $extra));
|
||||
}
|
||||
|
||||
return static function (...$args) use ($callable, $arguments, $placeholders) {
|
||||
return static function (...$args) use ($callable, $arguments, $placeholders, $extra) {
|
||||
$args = array_values($args);
|
||||
$count = min(count($placeholders), count($args));
|
||||
|
||||
@ -84,7 +93,7 @@ class PartiallyAppliedFunction implements Decorator, Compilable
|
||||
$arguments[$placeholders[$i]] = $args[$i];
|
||||
}
|
||||
|
||||
return $callable(...$arguments, ...array_slice($args, $count));
|
||||
return $callable(...$arguments, ...array_slice($args, $count, $extra));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +38,11 @@ class CallbackTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertSame(['v', 'k'], callback(fn (...$args) => $args)('v', 'k'));
|
||||
}
|
||||
|
||||
public function testPartialOfInternalFunctionDoesNotGetKey()
|
||||
{
|
||||
$this->assertSame('a', callback(f\partial(trim(...), _, 'x'))('xax', 'key'));
|
||||
}
|
||||
|
||||
public function testDecoratorIsCompiled()
|
||||
{
|
||||
$callback = callback(f\partial(fn ($prefix, $v, $k) => "$prefix$k=$v", '>'));
|
||||
|
||||
@ -88,6 +88,21 @@ class CompileTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertSame($partial(), f\compile($partial)());
|
||||
}
|
||||
|
||||
public function testCompileDropsExtraArgumentsForInternalTarget()
|
||||
{
|
||||
$this->assertSame('aa', f\compile(f\partial(str_repeat(...), _, 2))('a', 'extra'));
|
||||
}
|
||||
|
||||
public function testCompileKeepsExtraArgumentsForVariadicInternalTarget()
|
||||
{
|
||||
$this->assertSame(['a', 'b', 'c'], f\compile(f\partial(array_merge(...), ['a']))(['b'], ['c']));
|
||||
}
|
||||
|
||||
public function testCompileDropsExtraArgumentsForCurriedInternalTarget()
|
||||
{
|
||||
$this->assertSame('aa', f\compile(f\curry(str_repeat(...), null, 'a'))(2, 'extra'));
|
||||
}
|
||||
|
||||
public function testCompileFunctionDelegatesToMethod()
|
||||
{
|
||||
$partial = f\partial(str_replace(...), 'a', _, 'banana');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user