diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 86e6d206..cd3339ed 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -15,4 +15,8 @@
*/src/*/Abstract*.php
+
+
+ */src/DocBlock/Tags/InvalidTag.php
+
diff --git a/src/DocBlock/Tags/InvalidTag.php b/src/DocBlock/Tags/InvalidTag.php
index 9f632cb3..e3deb5a8 100644
--- a/src/DocBlock/Tags/InvalidTag.php
+++ b/src/DocBlock/Tags/InvalidTag.php
@@ -8,12 +8,13 @@
use Exception;
use phpDocumentor\Reflection\DocBlock\Tag;
use ReflectionClass;
+use ReflectionException;
use ReflectionFunction;
use Throwable;
use function array_map;
-use function array_walk_recursive;
use function get_class;
use function get_resource_type;
+use function is_array;
use function is_object;
use function is_resource;
use function sprintf;
@@ -80,29 +81,12 @@ private function flattenExceptionBacktrace(Throwable $exception) : void
$traceProperty = (new ReflectionClass(Exception::class))->getProperty('trace');
$traceProperty->setAccessible(true);
- $flatten =
- /** @param mixed $value */
- static function (&$value) : void {
- 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 = $exception->getTrace();
if (isset($trace[0]['args'])) {
$trace = array_map(
- static function (array $call) use ($flatten) : array {
- array_walk_recursive($call['args'], $flatten);
+ function (array $call) : array {
+ $call['args'] = array_map([$this, 'flattenArguments'], $call['args']);
return $call;
},
@@ -117,6 +101,33 @@ static function (array $call) use ($flatten) : array {
$traceProperty->setAccessible(false);
}
+ /**
+ * @param mixed $value
+ *
+ * @return mixed
+ *
+ * @throws ReflectionException
+ */
+ private function flattenArguments($value)
+ {
+ 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));
+ } elseif (is_array($value)) {
+ $value = array_map([$this, 'flattenArguments'], $value);
+ }
+
+ return $value;
+ }
+
public function render(?Formatter $formatter = null) : string
{
if ($formatter === null) {
diff --git a/tests/integration/ModifyBackTraceSafeTest.php b/tests/integration/ModifyBackTraceSafeTest.php
new file mode 100644
index 00000000..bdc2dc85
--- /dev/null
+++ b/tests/integration/ModifyBackTraceSafeTest.php
@@ -0,0 +1,75 @@
+children[] = new Node();
+ $node1->children[] = new Node();
+
+ $traverser->traverse([new Node(), $node1]);
+ }
+}
+
+
+class Node {
+ public $children = [];
+}
+
+class Traverser
+{
+ public function traverse(array $nodes)
+ {
+ $this->traverseArray($nodes);
+ }
+
+ public function traverseArray(array $nodes): array
+ {
+ $doNodes = [];
+
+ foreach ($nodes as &$node) {
+ $node = $this->callback($node);
+ $node = $this->traverseNode($node);
+
+ $doNodes[] = $node;
+ }
+
+ return $doNodes;
+ }
+
+ public function callback(Node $class) : Node
+ {
+ $docblock = <<create($docblock);
+
+ return $class;
+ }
+
+ private function traverseNode(Node $node) : Node
+ {
+ if ($node->children) {
+ $this->traverseArray($node->children);
+ }
+
+ return $node;
+ }
+}