Skip to content

Handle recursive and repeated arrays more gracefully when exporting - #773

Merged
sebastianbergmann merged 12 commits into
sebastianbergmann:masterfrom
LawnGnome:recursive-export
Jan 8, 2013
Merged

Handle recursive and repeated arrays more gracefully when exporting#773
sebastianbergmann merged 12 commits into
sebastianbergmann:masterfrom
LawnGnome:recursive-export

Conversation

@LawnGnome

Copy link
Copy Markdown
Contributor

This PR largely replaces PHPUnit_Util_Type::recursiveExport() with a more robust implementation that doesn't rely on print_r() to detect array recursion.

Test suites that have heavily nested arrays don't seem to have recursion picked up completely reliably — this seems to particularly manifest itself when dealing with codebases that use Symfony 2 and Doctrine ORM, where the proxied entity objects often include recursed and repeated arrays. As a result, when an assertion fails and the data structure has to be exported, PHP typically runs out of memory while looping infinitely. (For example, my memory_limit is set to 8G. At the risk of invoking Bill Gates, that should be enough for anyone.)

This implementation uses a completely userland approach to detect array recursion, and keeps the list of previously seen arrays and objects in a new context object (which also uses SplObjectStorage for more efficient storage of the seen object set).

The output format of recursiveExport() has changed in this PR: arrays now include a numeric ID, and objects now include a hexadecimal hash from spl_object_hash(). The initial reference to an array or object will dump the entire array or object as it does now, while subsequent references will simply show the ID/hash.

@sebastianbergmann
sebastianbergmann merged commit 9267b0b into sebastianbergmann:master Jan 8, 2013
@sebastianbergmann

Copy link
Copy Markdown
Owner

Thanks!

I do get the following failure on my machine:

➜  phpunit git:(master) phpunit
PHPUnit 3.8-g562045c by Sebastian Bergmann.

Configuration read from /usr/local/src/phpunit/phpunit.xml.dist

...............................................................  63 / 939 (  6%)
............................................................... 126 / 939 ( 13%)
............................................................... 189 / 939 ( 20%)
............................................................... 252 / 939 ( 26%)
............................................................... 315 / 939 ( 33%)
............................................................... 378 / 939 ( 40%)
............................................................... 441 / 939 ( 46%)
............................................................... 504 / 939 ( 53%)
............................................................... 567 / 939 ( 60%)
............................................................... 630 / 939 ( 67%)
.............F................................................. 693 / 939 ( 73%)
............................................................... 756 / 939 ( 80%)
............................................................... 819 / 939 ( 87%)
............................................................... 882 / 939 ( 93%)
.........................................................

Time: 38 seconds, Memory: 64.50Mb

There was 1 failure:

1) Framework_ConstraintTest::testConstraintIsEqual2 with data set #13 (SplObjectStorage, SplObjectStorage, 'Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
-SplObjectStorage Object &000000006725cab800000000778c5e15 (
-    \'000000006725caa600000000778df095\' => Array &0 (
-        \'obj\' => stdClass Object &000000006725caa600000000778df095 (
-            \'foo\' => \'bar\'
-        )
+SplObjectStorage Object &000000006725cab900000000778c5e15 (
+    \'000000006725caa700000000778df095\' => Array &0 (
+        \'obj\' => stdClass Object &000000006725caa700000000778df095 ()
         \'inf\' => null
     )
-    \'000000006725caa700000000778df095\' => Array &0
 )
')
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
 -SplObjectStorage Object &000000006725cab800000000778c5e15 (
--    '000000006725caa600000000778df095' => Array &0 (
--        'obj' => stdClass Object &000000006725caa600000000778df095 (
++SplObjectStorage Object &000000006725cab900000000778c5e15 (
+     Binary String: 0x00676364617461 => Array &0 (
+-        0 => stdClass Object &000000006725caa600000000778df095 (
 -            'foo' => 'bar'
 -        )
-+SplObjectStorage Object &000000006725cab900000000778c5e15 (
-+    '000000006725caa700000000778df095' => Array &0 (
-+        'obj' => stdClass Object &000000006725caa700000000778df095 ()
-         'inf' => null
++        0 => stdClass Object &000000006725caa700000000778df095 ()
+         1 => null
+-        2 => stdClass Object &000000006725caa700000000778df095 ()
+-        3 => null
      )
--    '000000006725caa700000000778df095' => Array &0
+-    '000000006725caa600000000778df095' => Array &0
+     '000000006725caa700000000778df095' => Array &0
  )
 '

/usr/local/src/phpunit/PHPUnit/Framework/Constraint/IsEqual.php:170
/usr/local/src/phpunit/PHPUnit/Framework/Assert.php:2134
/usr/local/src/phpunit/PHPUnit/Framework/Assert.php:475
/usr/local/src/phpunit/Tests/Framework/ConstraintTest.php:946
/usr/local/src/phpunit/PHPUnit/Framework/TestCase.php:975
/usr/local/src/phpunit/PHPUnit/Framework/TestCase.php:830
/usr/local/src/phpunit/PHPUnit/Framework/TestResult.php:646
/usr/local/src/phpunit/PHPUnit/Framework/TestCase.php:775
/usr/local/src/phpunit/PHPUnit/Framework/TestSuite.php:775
/usr/local/src/phpunit/PHPUnit/Framework/TestSuite.php:745
/usr/local/src/phpunit/PHPUnit/Framework/TestSuite.php:705
/usr/local/src/phpunit/PHPUnit/Framework/TestSuite.php:705
/usr/local/src/phpunit/PHPUnit/TextUI/TestRunner.php:350
/usr/local/src/phpunit/PHPUnit/TextUI/Command.php:176
/usr/local/src/phpunit/PHPUnit/TextUI/Command.php:129

FAILURES!
Tests: 939, Assertions: 1523, Failures: 1.

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

Any idea?

@LawnGnome

Copy link
Copy Markdown
Contributor Author

I can't reproduce it locally. What version of PHP are you running?

@sebastianbergmann

Copy link
Copy Markdown
Owner
➜  ~  php -v
PHP 5.4.12-dev (cli) (built: Jan  9 2013 06:13:47) (DEBUG)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
    with Xdebug v2.3.0dev, Copyright (c) 2002-2012, by Derick Rethans

➜  ~  php-5.5 -v         
PHP 5.5.0-dev (cli) (built: Jan  9 2013 06:15:05) (DEBUG)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.5.0-dev, Copyright (c) 1998-2013 Zend Technologies
    with Xdebug v2.3.0dev, Copyright (c) 2002-2012, by Derick Rethans

falkenhawk added a commit to zf1s/phpunit that referenced this pull request May 8, 2019
- to avoid looping/memory leaks/segfaults on PHP 7.x
- Alter PHPUnit_Util_Type::recursiveExport() to handle repeated and recursive data structures more gracefully (and with less memory usage).
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Jul 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants