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 string callable in case of non-static method #821

Merged
merged 16 commits into from
Oct 14, 2019
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Fix deprecation raised when serializing callable in certain circumstances (#821)

## 2.2.2 (2019-10-10)

- Fix handling of fifth argument in the error handler (#892)
Expand Down
39 changes: 35 additions & 4 deletions src/Serializer/AbstractSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

namespace Sentry\Serializer;

use Sentry\Exception\InvalidArgumentException;
use Sentry\Options;

/**
Expand Down Expand Up @@ -102,7 +103,7 @@ protected function serializeRecursively($value, int $_depth = 0)
}

if (\is_callable($value)) {
return $this->serializeCallable($value);
return $this->serializeCallableWithoutTypeHint($value);
}

if (\is_array($value)) {
Expand Down Expand Up @@ -250,7 +251,7 @@ protected function serializeValue($value)
}

if (\is_callable($value)) {
return $this->serializeCallable($value);
return $this->serializeCallableWithoutTypeHint($value);
}

if (\is_array($value)) {
Expand All @@ -261,7 +262,37 @@ protected function serializeValue($value)
}

/**
* @param callable $callable
* This method is provided as a non-BC upgrade of serializeCallable,
* since using the callable type raises a deprecation in some cases.
*
* @param callable|mixed $callable
*
* @return string
*/
protected function serializeCallableWithoutTypeHint($callable): string
{
if (\is_string($callable) && !\function_exists($callable)) {
return $callable;
}

if (!\is_callable($callable)) {
throw new InvalidArgumentException(sprintf(
'Expecting callable, got %s',
\is_object($callable)
? \get_class($callable)
: \gettype($callable)
));
}

return $this->serializeCallable($callable);
}

/**
* Use serializeCallableWithoutTypeHint instead (no type in argument).
*
* @see https://github.com/getsentry/sentry-php/pull/821
*
* @param callable $callable callable type to be removed in 3.0, see #821
*
* @return string
*/
Expand All @@ -271,7 +302,7 @@ protected function serializeCallable(callable $callable): string
if (\is_array($callable)) {
$reflection = new \ReflectionMethod($callable[0], $callable[1]);
$class = $reflection->getDeclaringClass();
} elseif ($callable instanceof \Closure || \is_string($callable)) {
} elseif ($callable instanceof \Closure || (\is_string($callable) && \function_exists($callable))) {
$reflection = new \ReflectionFunction($callable);
$class = null;
} elseif (\is_object($callable) && method_exists($callable, '__invoke')) {
Expand Down
5 changes: 3 additions & 2 deletions src/Stacktrace.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,9 @@ protected function getFrameArgumentsValues(array $frame): array
if (\is_string(array_keys($frame['args'])[0])) {
$result = array_map([$this, 'serializeArgument'], $frame['args']);
} else {
foreach (array_values($frame['args']) as $index => $argument) {
$result['param' . ($index + 1)] = $this->serializeArgument($argument);
$index = 0;
foreach (array_values($frame['args']) as $argument) {
$result['param' . (++$index)] = $this->serializeArgument($argument);
}
}

Expand Down
6 changes: 5 additions & 1 deletion tests/Serializer/AbstractSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,17 @@ public function serializableCallableProvider(): array
'callable' => $callableWithoutNamespaces,
'expected' => 'Lambda void {closure} [int|null param1_70ns]',
],
[
'callable' => __METHOD__,
'expected' => __METHOD__,
],
];
}

/**
* @dataProvider serializableCallableProvider
*/
public function testSerializeCallable(callable $callable, string $expected): void
public function testSerializeCallable($callable, string $expected): void
{
$serializer = $this->createSerializer();
$actual = $this->invokeSerialization($serializer, $callable);
Expand Down