Skip to content

Commit

Permalink
added support for variadic arguments in proxied class methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mfris committed Jul 29, 2022
1 parent 22ee744 commit 01bf890
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
matrix:
php-version: [ '8.0', '8.1' ]
symfony-version: [ '5.4.*', '6.*' ]
symfony-deprecations-helper: [ 'max[direct]=0' ]
symfony-deprecations-helper: [ 'max[direct]=0&max[indirect]=99999' ]
grumphp-testsuite: [ 'no-analyse' ]
include:
- php-version: '7.4'
Expand Down
1 change: 1 addition & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</coverage>
<php>
<ini name="error_reporting" value="-1"/>
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[direct]=0&amp;max[indirect]=99999"/>
</php>
<listeners>
<listener class="\Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
Expand Down
51 changes: 49 additions & 2 deletions src/Instantiator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PixelFederation\CircuitBreakerBundle\Exception\ServiceIsNotAvailable;
use ProxyManager\Signature\Exception\InvalidSignatureException;
use ProxyManager\Signature\Exception\MissingSignatureException;
use ReflectionClass;

/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
Expand All @@ -27,6 +28,11 @@ final class Instantiator

private CircuitBreaker $circuitBreaker;

/**
* @var array<string, bool>
*/
private array $variadicParamsCache = [];

public function __construct(
MethodExtractor $methodExtractor,
Generator $proxyGenerator,
Expand Down Expand Up @@ -77,15 +83,15 @@ private function getCallback(
return function (
$proxy,
object $instance,
$method,
string $method,
array $params,
&$returnEarly
) use (
$configuration,
$serviceMethod,
$serviceMethods
) {
$params = array_values($params); // fix for php 8 and named parameters
$params = $this->processInvokerParameters($instance, $method, $params);
/** @var Callable $callable */
$callable = [$instance, $method];
$invoker = static fn () => call_user_func_array($callable, $params);
Expand All @@ -100,6 +106,47 @@ private function getCallback(
};
}

/**
* if the last of the callback parameters is variadic, the parameters array needs to be changed accordingly
*
* @param array<mixed|iterable<mixed>> $params
* @return array<mixed>
*/
private function processInvokerParameters(object $instance, string $method, array $params): array
{
$params = array_values($params); // fix for php 8 and named parameters

if (!$this->isLastMethodParamVariadic($instance, $method)) {
return $params;
}

/** @var iterable<mixed> $lastParam */
$lastParam = array_pop($params);

return [...$params, ...$lastParam];
}

private function isLastMethodParamVariadic(object $instance, string $method): bool
{
$cacheKey = sprintf('%s::%s', get_class($instance), $method);

if (isset($this->variadicParamsCache[$cacheKey])) {
return $this->variadicParamsCache[$cacheKey];
}

$reflClass = new ReflectionClass($instance);
$reflMethod = $reflClass->getMethod($method);
$methodParams = $reflMethod->getParameters();

if (empty($methodParams)) {
return false;
}

$lastMethodParam = array_pop($methodParams);

return $this->variadicParamsCache[$cacheKey] = $lastMethodParam->isVariadic();
}

/**
* @param array<mixed> $params @codingStandardsIgnoreLine
*/
Expand Down

0 comments on commit 01bf890

Please sign in to comment.