diff --git a/src/Whoops/Exception/Frame.php b/src/Whoops/Exception/Frame.php index a97268e..d2da5b5 100644 --- a/src/Whoops/Exception/Frame.php +++ b/src/Whoops/Exception/Frame.php @@ -225,4 +225,8 @@ class Frame implements Serializable $this->frame = $frame; } + + public function equals(Frame $frame){ + return $frame->getFile() == $this->getFile() && $frame->getLine() === $this->getLine(); + } } diff --git a/src/Whoops/Exception/FrameCollection.php b/src/Whoops/Exception/FrameCollection.php index c5fb7bc..e39cdfa 100644 --- a/src/Whoops/Exception/FrameCollection.php +++ b/src/Whoops/Exception/FrameCollection.php @@ -119,4 +119,36 @@ class FrameCollection implements IteratorAggregate, Serializable, Countable { $this->frames = unserialize($serializedFrames); } + + /** + * @param Frame[] $frames Array of Frame instances, usually from $e->getPrevious() + */ + public function prependFrames(array $frames) + { + $this->frames = array_merge($frames, $this->frames); + } + + /** + * Gets the innermost part of stack trace that is not the same as that of outer exception + * + * @param FrameCollection $parentFrames Outer exception frames to compare tail against + * @return Frame[] + */ + public function topDiff(FrameCollection $parentFrames) + { + $diff = $this->frames; + + $parentFrames = $parentFrames->getArray(); + $p = count($parentFrames)-1; + + for($i = count($diff)-1; $i >= 0 && $p >= 0; $i--) { + /** @var Frame $tailFrame */ + $tailFrame = $diff[$i]; + if($tailFrame->equals($parentFrames[$p])) { + unset($diff[$i]); + } + $p--; + } + return $diff; + } } diff --git a/src/Whoops/Exception/Inspector.php b/src/Whoops/Exception/Inspector.php index 19408dd..074fcfa 100644 --- a/src/Whoops/Exception/Inspector.php +++ b/src/Whoops/Exception/Inspector.php @@ -5,8 +5,6 @@ */ namespace Whoops\Exception; -use Whoops\Exception\FrameCollection; -use Whoops\Exception\ErrorException; use Exception; class Inspector @@ -17,12 +15,12 @@ class Inspector private $exception; /** - * @var Whoops\Exception\FrameCollection + * @var \Whoops\Exception\FrameCollection */ private $frames; /** - * @var Whoops\Exception\Inspector + * @var \Whoops\Exception\Inspector */ private $previousExceptionInspector; @@ -70,7 +68,7 @@ class Inspector /** * Returns an inspector for a previous inspector, if any. * @todo Clean this up a bit, cache stuff a bit better. - * @return Whoops\Exception\Inspector|null + * @return \Whoops\Exception\Inspector|null */ public function getPreviousExceptionInspector() { @@ -88,7 +86,7 @@ class Inspector /** * Returns an iterator for the inspected exception's * frames. - * @return Whoops\Exception\FrameCollection + * @return \Whoops\Exception\FrameCollection */ public function getFrames() { @@ -107,11 +105,16 @@ class Inspector array_unshift($frames, $firstFrame); } $this->frames = new FrameCollection($frames); + + if ($previousInspector = $this->getPreviousExceptionInspector()) { + $this->frames->prependFrames($previousInspector->getFrames()->topDiff($this->frames)); + } } return $this->frames; } + /** * Given an exception, generates an array in the format * generated by Exception::getTrace() diff --git a/tests/Whoops/Exception/FrameCollectionTest.php b/tests/Whoops/Exception/FrameCollectionTest.php index 136d115..211f31b 100644 --- a/tests/Whoops/Exception/FrameCollectionTest.php +++ b/tests/Whoops/Exception/FrameCollectionTest.php @@ -147,4 +147,26 @@ class FrameCollectionTest extends TestCase $this->assertInstanceOf('Whoops\\Exception\\Frame', $frame); } } + + + /** + * @covers Whoops\Exception\FrameCollection::topDiff + */ + public function testTopDiff(){ + $commonFrameTail = $this->getFrameDataList(3); + + $diffFrame = array('line' => $this->frameIdCounter) + $this->getFrameData(); + + $frameCollection1 = new FrameCollection(array_merge(array( + $diffFrame + ), $commonFrameTail)); + + $frameCollection2 = new FrameCollection(array_merge(array( + $this->getFrameData() + ), $commonFrameTail)); + + $diff = $frameCollection1->topDiff($frameCollection2); + + $this->assertCount(1, $diff); + } } diff --git a/tests/Whoops/Exception/FrameTest.php b/tests/Whoops/Exception/FrameTest.php index d615ae0..0460e34 100644 --- a/tests/Whoops/Exception/FrameTest.php +++ b/tests/Whoops/Exception/FrameTest.php @@ -206,4 +206,13 @@ class FrameTest extends TestCase $this->assertEquals($comments[0]["comment"], $commentText); $this->assertEquals($comments[0]["context"], $commentContext); } + + /** + * @covers Whoops\Exception\Frame::equals + */ + public function testEquals(){ + $frame1 = $this->getFrameInstance(array('line' => 1, 'file' => 'test-file.php')); + $frame2 = $this->getFrameInstance(array('line' => 1, 'file' => 'test-file.php')); + $this->assertTrue ($frame1->equals($frame2)); + } }