Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle variadic and not declared arguments in stack traces #1650

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 61 additions & 5 deletions src/FrameBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
*/
private $representationSerializer;

/**
* @var string The default name for function parameters when we cannot get
* them from function definition
*/
private const DEFAULT_PARAMETER_NAME = 'param';

/**
* Constructor.
*
Expand Down Expand Up @@ -174,7 +180,7 @@
$argumentValues = $this->getFunctionArgumentValues($reflectionFunction, $backtraceFrame['args']);
} else {
foreach ($backtraceFrame['args'] as $parameterPosition => $parameterValue) {
$argumentValues['param' . $parameterPosition] = $parameterValue;
$argumentValues[self::DEFAULT_PARAMETER_NAME . $parameterPosition] = $parameterValue;
}
}

Expand All @@ -198,16 +204,66 @@
{
$argumentValues = [];

// $backtraceFrameArgs can contain string keys if function has
// variadic parameters and we passed them by name. Because of this,
// we cannot use indexes to access our values.
// Using foreach here will complicate logic for handling variadic and
// undeclared arguments, so we have to use iterator.
reset($backtraceFrameArgs);

$variadicParameter = null;
foreach ($reflectionFunction->getParameters() as $reflectionParameter) {
$parameterPosition = $reflectionParameter->getPosition();
// We want to handle variadic parameters separately,
// so we remember it and break out of the loop.
if ($reflectionParameter->isVariadic()) {
$variadicParameter = $reflectionParameter;
break;
}

if (!isset($backtraceFrameArgs[$parameterPosition])) {
continue;
if (key($backtraceFrameArgs) !== null) {
$value = current($backtraceFrameArgs);
next($backtraceFrameArgs);
} elseif ($reflectionParameter->isDefaultValueAvailable()) {
$value = $reflectionParameter->getDefaultValue();
} else {
// In theory, we will only end up here if not enough arguments
// were passed to the function (ArgumentCountError).
// In this case we can break out of the loop and let next
// condition handle returning result.
break;
}

$argumentValues[$reflectionParameter->getName()] = $backtraceFrameArgs[$parameterPosition];
$argumentValues[$reflectionParameter->getName()] = $value;
}

// Return if we reached the end of supplied args, so we don't
// waste time handling things, which aren't there.
if (key($backtraceFrameArgs) === null) {
return $argumentValues;
}

if ($variadicParameter !== null) {
// If we have variadic parameters, we will write them into an
// array, since this is how they appear inside of function they
// were passed to.
$variadicArgs = [];
while (key($backtraceFrameArgs) !== null) {
$variadicArgs[key($backtraceFrameArgs)] = current($backtraceFrameArgs);
next($backtraceFrameArgs);
}
$argumentValues[$variadicParameter->getName()] = $variadicArgs;

Check failure on line 254 in src/FrameBuilder.php

View workflow job for this annotation

GitHub Actions / PHPStan

Unreachable statement - code above always terminates.
} else {
// If we don't have variadic parameter, but still have additional
// arguments, it means those arguments weren't declared in a function.
// We will name them the same way it's done when we can't create
// function reflection.
while (key($backtraceFrameArgs) !== null) {
$argumentKey = self::DEFAULT_PARAMETER_NAME . key($backtraceFrameArgs);
$argumentValues[$argumentKey] = current($backtraceFrameArgs);
next($backtraceFrameArgs);
}
}

return $argumentValues;

Check failure on line 267 in src/FrameBuilder.php

View workflow job for this annotation

GitHub Actions / PHPStan

Unreachable statement - code above always terminates.
}
}
Loading