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;
|
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
|
public function compile(): \Closure
|
||||||
{
|
{
|
||||||
$callable = compile($this->callable);
|
$callable = compile($this->callable);
|
||||||
$arguments = $this->arguments;
|
$arguments = $this->arguments;
|
||||||
$placeholders = array_keys($arguments, PLACEHOLDER, true);
|
$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)) {
|
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);
|
$args = array_values($args);
|
||||||
$count = min(count($placeholders), count($args));
|
$count = min(count($placeholders), count($args));
|
||||||
|
|
||||||
@ -84,7 +93,7 @@ class PartiallyAppliedFunction implements Decorator, Compilable
|
|||||||
$arguments[$placeholders[$i]] = $args[$i];
|
$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'));
|
$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()
|
public function testDecoratorIsCompiled()
|
||||||
{
|
{
|
||||||
$callback = callback(f\partial(fn ($prefix, $v, $k) => "$prefix$k=$v", '>'));
|
$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)());
|
$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()
|
public function testCompileFunctionDelegatesToMethod()
|
||||||
{
|
{
|
||||||
$partial = f\partial(str_replace(...), 'a', _, 'banana');
|
$partial = f\partial(str_replace(...), 'a', _, 'banana');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user