Skip to content

Instantly share code, notes, and snippets.

@Thinkscape
Last active September 6, 2024 18:45
Show Gist options
  • Save Thinkscape/805ba8b91cdce6bcaf7c to your computer and use it in GitHub Desktop.
Save Thinkscape/805ba8b91cdce6bcaf7c to your computer and use it in GitHub Desktop.
Make any PHP Exception serializable by flattening complex values in backtrace.
<?php
function flattenExceptionBacktrace(\Exception $exception) {
$traceProperty = (new \ReflectionClass('Exception'))->getProperty('trace');
$traceProperty->setAccessible(true);
$flatten = function(&$value, $key) {
if ($value instanceof \Closure) {
$closureReflection = new \ReflectionFunction($value);
$value = sprintf(
'(Closure at %s:%s)',
$closureReflection->getFileName(),
$closureReflection->getStartLine()
);
} elseif (is_object($value)) {
$value = sprintf('object(%s)', get_class($value));
} elseif (is_resource($value)) {
$value = sprintf('resource(%s)', get_resource_type($value));
}
};
do {
$trace = $traceProperty->getValue($exception);
foreach($trace as &$call) {
array_walk_recursive($call['args'], $flatten);
}
$traceProperty->setValue($exception, $trace);
} while($exception = $exception->getPrevious());
$traceProperty->setAccessible(false);
}
@zaka786khan
Copy link

zaka786khan commented Mar 7, 2023

I did following to convert an exception into an array to be logged as json. Here I didn't care arguments

public function exceptiontoArray(null|Exception $exception)
{
    if($exception) {
      return [
        'message' => $exception->getMessage(),
        'file' => $exception->getFile(),
        'line' => $exception->getLine(),
        'trace' => $exception->getTrace(),
        'previous' => exceptiontoArray($exception->getPrevious())
      ];
    } else {
      return [];
    }
}

@xpader
Copy link

xpader commented Dec 28, 2023

I use ReflectionObject to serialize exception, this dropped non-scalar properties, be careful.

function object2ScalarArray(object $object)
{
    $ref = new \ReflectionObject($object);

    $props = [];
    foreach ($ref->getProperties() as $prop) {
        $prop->setAccessible(true);
        $val = $prop->getValue($object);
        if (is_scalar($val)) {
            $props[$prop->getName()] = $val;
        }
    }

    return [
        'class' => $object::class,
        'props' => $props
    ];
}

function scalarArray2Object(array $scalarArray)
{
    $ref = new \ReflectionClass($scalarArray['class']);
    $object = $ref->newInstanceWithoutConstructor();

    $ref = new \ReflectionObject($object);

    foreach ($scalarArray['props'] as $name => $val) {
        $prop = $ref->getProperty($name);
        $prop->setAccessible(true);
        $prop->setValue($object, $val);
    }

    return $object;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment