From aba3a3ac211ee21e5eb20781a296c859c4163ce6 Mon Sep 17 00:00:00 2001 From: DonCallisto Date: Fri, 2 Nov 2018 20:29:45 +0100 Subject: [PATCH] Introduced and fixed CachedDoubler behaviour in order to reduce memory usage --- .../Argument/ArgumentsWildcardSpec.php | 5 ++++- .../Argument/Token/ExactValueTokenSpec.php | 8 +++++--- .../Argument/Token/IdenticalValueTokenSpec.php | 8 +++++--- .../ClassPatch/ProphecySubjectPatchSpec.php | 4 ++-- spec/Prophecy/Util/StringUtilSpec.php | 5 +++-- src/Prophecy/Doubler/CachedDoubler.php | 18 ++++-------------- .../ClassPatch/ProphecySubjectPatch.php | 6 +++--- src/Prophecy/Prophet.php | 11 +++++++---- src/Prophecy/Util/ExportUtil.php | 4 +--- 9 files changed, 34 insertions(+), 35 deletions(-) diff --git a/spec/Prophecy/Argument/ArgumentsWildcardSpec.php b/spec/Prophecy/Argument/ArgumentsWildcardSpec.php index b82f1b893..4daa0b0b3 100644 --- a/spec/Prophecy/Argument/ArgumentsWildcardSpec.php +++ b/spec/Prophecy/Argument/ArgumentsWildcardSpec.php @@ -14,7 +14,10 @@ function it_wraps_non_token_arguments_into_ExactValueToken(\stdClass $object) $class = get_class($object->getWrappedObject()); $hash = spl_object_hash($object->getWrappedObject()); - $this->__toString()->shouldReturn("exact(42), exact(\"zet\"), exact($class:$hash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + $objHash = "exact(42), exact(\"zet\"), exact($class:$hash Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } function it_generates_string_representation_from_all_tokens_imploded( diff --git a/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php b/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php index 14322f829..357c05b7f 100644 --- a/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php +++ b/spec/Prophecy/Argument/Token/ExactValueTokenSpec.php @@ -125,13 +125,15 @@ function it_generates_proper_string_representation_for_resource() function it_generates_proper_string_representation_for_object(\stdClass $object) { - $objHash = sprintf('%s:%s', + $objHash = sprintf('exact(%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ); + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; $this->beConstructedWith($object); - $this->__toString()->shouldReturn("exact($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } } diff --git a/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php b/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php index 00c3a2157..42625b695 100644 --- a/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php +++ b/spec/Prophecy/Argument/Token/IdenticalValueTokenSpec.php @@ -141,12 +141,14 @@ function it_generates_proper_string_representation_for_resource() function it_generates_proper_string_representation_for_object($object) { - $objHash = sprintf('%s:%s', + $objHash = sprintf('identical(%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ); + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n))"; $this->beConstructedWith($object); - $this->__toString()->shouldReturn("identical($objHash Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n))"); + + $hashRegexExpr = '[a-f0-9]{32}'; + $this->__toString()->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } } diff --git a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php index ef1c254ed..87e4fd099 100644 --- a/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php +++ b/spec/Prophecy/Doubler/ClassPatch/ProphecySubjectPatchSpec.php @@ -28,7 +28,7 @@ function it_forces_class_to_implement_ProphecySubjectInterface(ClassNode $node) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->shouldBeCalled(); - $node->addProperty('objectProphecy', 'private')->willReturn(null); + $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); $node->getMethods()->willReturn(array()); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); @@ -45,7 +45,7 @@ function it_forces_all_class_methods_except_constructor_to_proxy_calls_into_prop MethodNode $method3 ) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface')->willReturn(null); - $node->addProperty('objectProphecy', 'private')->willReturn(null); + $node->addProperty('objectProphecyClosure', 'private')->willReturn(null); $node->hasMethod(Argument::any())->willReturn(false); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); $node->addMethod(Argument::type('Prophecy\Doubler\Generator\Node\MethodNode'), true)->willReturn(null); diff --git a/spec/Prophecy/Util/StringUtilSpec.php b/spec/Prophecy/Util/StringUtilSpec.php index 80573cffb..923f09af1 100644 --- a/spec/Prophecy/Util/StringUtilSpec.php +++ b/spec/Prophecy/Util/StringUtilSpec.php @@ -74,9 +74,10 @@ function it_generates_proper_string_representation_for_object(\stdClass $object) $objHash = sprintf('%s:%s', get_class($object->getWrappedObject()), spl_object_hash($object->getWrappedObject()) - ) . " Object (\n 'objectProphecy' => Prophecy\Prophecy\ObjectProphecy Object (*Prophecy*)\n)"; + ) . " Object (\n 'objectProphecyClosure' => Closure:%s Object (\n 0 => Closure:%s Object\n )\n)"; - $this->stringify($object)->shouldReturn("$objHash"); + $hashRegexExpr = '[a-f0-9]{32}'; + $this->stringify($object)->shouldMatch(sprintf('/^%s$/', sprintf(preg_quote("$objHash"), $hashRegexExpr, $hashRegexExpr))); } function it_generates_proper_string_representation_for_object_without_exporting(\stdClass $object) diff --git a/src/Prophecy/Doubler/CachedDoubler.php b/src/Prophecy/Doubler/CachedDoubler.php index d6b6b1a9e..22ab71afd 100644 --- a/src/Prophecy/Doubler/CachedDoubler.php +++ b/src/Prophecy/Doubler/CachedDoubler.php @@ -21,17 +21,7 @@ */ class CachedDoubler extends Doubler { - private $classes = array(); - - /** - * {@inheritdoc} - */ - public function registerClassPatch(ClassPatch\ClassPatchInterface $patch) - { - $this->classes[] = array(); - - parent::registerClassPatch($patch); - } + private static $classes = array(); /** * {@inheritdoc} @@ -39,11 +29,11 @@ public function registerClassPatch(ClassPatch\ClassPatchInterface $patch) protected function createDoubleClass(ReflectionClass $class = null, array $interfaces) { $classId = $this->generateClassId($class, $interfaces); - if (isset($this->classes[$classId])) { - return $this->classes[$classId]; + if (isset(self::$classes[$classId])) { + return self::$classes[$classId]; } - return $this->classes[$classId] = parent::createDoubleClass($class, $interfaces); + return self::$classes[$classId] = parent::createDoubleClass($class, $interfaces); } /** diff --git a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php index 081dea82a..ef4036667 100644 --- a/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php +++ b/src/Prophecy/Doubler/ClassPatch/ProphecySubjectPatch.php @@ -43,7 +43,7 @@ public function supports(ClassNode $node) public function apply(ClassNode $node) { $node->addInterface('Prophecy\Prophecy\ProphecySubjectInterface'); - $node->addProperty('objectProphecy', 'private'); + $node->addProperty('objectProphecyClosure', 'private'); foreach ($node->getMethods() as $name => $method) { if ('__construct' === strtolower($name)) { @@ -65,10 +65,10 @@ public function apply(ClassNode $node) $prophecyArgument = new ArgumentNode('prophecy'); $prophecyArgument->setTypeHint('Prophecy\Prophecy\ProphecyInterface'); $prophecySetter->addArgument($prophecyArgument); - $prophecySetter->setCode('$this->objectProphecy = $prophecy;'); + $prophecySetter->setCode('$this->objectProphecyClosure = function () use ($prophecy) { return $prophecy; };'); $prophecyGetter = new MethodNode('getProphecy'); - $prophecyGetter->setCode('return $this->objectProphecy;'); + $prophecyGetter->setCode('return call_user_func($this->objectProphecyClosure);'); if ($node->hasMethod('__call')) { $__call = $node->getMethod('__call'); diff --git a/src/Prophecy/Prophet.php b/src/Prophecy/Prophet.php index a4fe4b0d2..d37c92a34 100644 --- a/src/Prophecy/Prophet.php +++ b/src/Prophecy/Prophet.php @@ -11,6 +11,7 @@ namespace Prophecy; +use Prophecy\Doubler\CachedDoubler; use Prophecy\Doubler\Doubler; use Prophecy\Doubler\LazyDouble; use Prophecy\Doubler\ClassPatch; @@ -45,11 +46,13 @@ class Prophet * @param null|RevealerInterface $revealer * @param null|StringUtil $util */ - public function __construct(Doubler $doubler = null, RevealerInterface $revealer = null, - StringUtil $util = null) - { + public function __construct( + Doubler $doubler = null, + RevealerInterface $revealer = null, + StringUtil $util = null + ) { if (null === $doubler) { - $doubler = new Doubler; + $doubler = new CachedDoubler(); $doubler->registerClassPatch(new ClassPatch\SplFileInfoPatch); $doubler->registerClassPatch(new ClassPatch\TraversablePatch); $doubler->registerClassPatch(new ClassPatch\ThrowablePatch); diff --git a/src/Prophecy/Util/ExportUtil.php b/src/Prophecy/Util/ExportUtil.php index 50dd3f325..1090a801e 100644 --- a/src/Prophecy/Util/ExportUtil.php +++ b/src/Prophecy/Util/ExportUtil.php @@ -181,9 +181,7 @@ protected static function recursiveExport(&$value, $indentation, $processed = nu if (is_object($value)) { $class = get_class($value); - if ($value instanceof ProphecyInterface) { - return sprintf('%s Object (*Prophecy*)', $class); - } elseif ($hash = $processed->contains($value)) { + if ($hash = $processed->contains($value)) { return sprintf('%s:%s Object', $class, $hash); }