avoid by-reference warnings in filter
This commit is contained in:
parent
71e1b2cbdc
commit
d013a84f90
@ -64,13 +64,17 @@ function callback(callable $callable, int $arity = 1): \Closure
|
|||||||
$leadingOnly = $target->isInternal()
|
$leadingOnly = $target->isInternal()
|
||||||
|| (!$target->isVariadic() && $target->getNumberOfParameters() === $arity);
|
|| (!$target->isVariadic() && $target->getNumberOfParameters() === $arity);
|
||||||
|
|
||||||
|
// Internal functions like array_filter() pass values, not variables, so a closure taking a parameter by reference
|
||||||
|
// would warn on each call. Called from a wrapper, it gets the wrapper's variables instead.
|
||||||
|
$reflection = new \ReflectionFunction($compiled);
|
||||||
|
$byReference = takesByReference($reflection);
|
||||||
|
|
||||||
if (!$leadingOnly) {
|
if (!$leadingOnly) {
|
||||||
return $compiled;
|
return $byReference ? static fn (...$args) => $compiled(...$args) : $compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A userland closure taking no more than the leading arguments already ignores the rest.
|
// A userland closure taking no more than the leading arguments already ignores the rest.
|
||||||
$reflection = new \ReflectionFunction($compiled);
|
if (!$byReference && !$reflection->isInternal() && !$reflection->isVariadic() && $reflection->getNumberOfParameters() <= $arity) {
|
||||||
if (!$reflection->isInternal() && !$reflection->isVariadic() && $reflection->getNumberOfParameters() <= $arity) {
|
|
||||||
return $compiled;
|
return $compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +83,22 @@ function callback(callable $callable, int $arity = 1): \Closure
|
|||||||
: static fn ($carry, $value) => $compiled($carry, $value);
|
: static fn ($carry, $value) => $compiled($carry, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a function takes any of its parameters by reference.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function takesByReference(\ReflectionFunction $reflection): bool
|
||||||
|
{
|
||||||
|
foreach ($reflection->getParameters() as $parameter) {
|
||||||
|
if ($parameter->isPassedByReference()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the function a callable ultimately calls: decorators are unwrapped, also when they were turned into
|
* Finds the function a callable ultimately calls: decorators are unwrapped, also when they were turned into
|
||||||
* closures, and a pipeline gives its first function, which gets all of its arguments.
|
* closures, and a pipeline gives its first function, which gets all of its arguments.
|
||||||
|
|||||||
@ -107,6 +107,29 @@ class TransformsTest extends \PHPUnit\Framework\TestCase
|
|||||||
$this->assertSeq([2], c\filter(fn ($v) => $v % 2 === 0)(self::gen([1, 2, 3])));
|
$this->assertSeq([2], c\filter(fn ($v) => $v % 2 === 0)(self::gen([1, 2, 3])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFilterWithByReferenceCallbackDoesNotWarn()
|
||||||
|
{
|
||||||
|
$warnings = [];
|
||||||
|
set_error_handler(function (int $level, string $message) use (&$warnings) {
|
||||||
|
$warnings[] = $message;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$array = c\filter(fn (&$v) => $v > 1)([1, 2, 3]);
|
||||||
|
$seq = c\filter(fn (&$v) => $v > 1)(new Seq([1, 2, 3]));
|
||||||
|
$both = c\filter(fn (&$v, $k) => $k > 0)([1, 2, 3]);
|
||||||
|
} finally {
|
||||||
|
restore_error_handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertSame([], $warnings);
|
||||||
|
$this->assertSame([1 => 2, 2 => 3], $array);
|
||||||
|
$this->assertSeq([2, 3], $seq);
|
||||||
|
$this->assertSame([1 => 2, 2 => 3], $both);
|
||||||
|
}
|
||||||
|
|
||||||
public function testFilterWithInternalPredicate()
|
public function testFilterWithInternalPredicate()
|
||||||
{
|
{
|
||||||
$this->assertSame([1 => 'a'], c\filter(is_string(...))([1, 'a']));
|
$this->assertSame([1 => 'a'], c\filter(is_string(...))([1, 'a']));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user