Skip to content

Commit 76d3909

Browse files
committed
Added StatelessFetchExceptionHandler cloning optimization in ConnectionContext.
Fixed type hints in ImportConnector from callable -> FetchExceptionHandler.
1 parent 9c8af41 commit 76d3909

File tree

5 files changed

+58
-13
lines changed

5 files changed

+58
-13
lines changed

src/Connector/ConnectionContext.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace ScriptFUSION\Porter\Connector;
33

44
use ScriptFUSION\Porter\Connector\FetchExceptionHandler\FetchExceptionHandler;
5+
use ScriptFUSION\Porter\Connector\FetchExceptionHandler\StatelessFetchExceptionHandler;
56

67
/**
78
* Specifies runtime connection settings and provides utility methods.
@@ -83,7 +84,7 @@ function (\Exception $exception) use (&$userHandlerCloned, &$providerHandlerClon
8384
*/
8485
private static function invokeHandler(FetchExceptionHandler &$handler, \Exception $exception, &$cloned)
8586
{
86-
if (!$cloned) {
87+
if (!$cloned && !$handler instanceof StatelessFetchExceptionHandler) {
8788
$handler = clone $handler;
8889
$handler->initialize();
8990
$cloned = true;

src/Connector/FetchExceptionHandler/StatelessFetchExceptionHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
namespace ScriptFUSION\Porter\Connector\FetchExceptionHandler;
33

44
/**
5-
* Contains a stateless fetch exception handler that does not respond to reset() calls.
5+
* Contains a fetch exception handler that does not have private state and therefore does not require initialization.
66
*/
77
final class StatelessFetchExceptionHandler implements FetchExceptionHandler
88
{

src/Connector/ImportConnector.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace ScriptFUSION\Porter\Connector;
33

44
use ScriptFUSION\Porter\Cache\CacheUnavailableException;
5+
use ScriptFUSION\Porter\Connector\FetchExceptionHandler\FetchExceptionHandler;
56

67
/**
78
* Connector whose lifecycle is synchronised with an import operation. Ensures correct ConnectionContext is delivered
@@ -43,9 +44,9 @@ public function getWrappedConnector()
4344
/**
4445
* Sets the exception handler to be called when a recoverable exception is thrown by Connector::fetch().
4546
*
46-
* @param callable $exceptionHandler Exception handler.
47+
* @param FetchExceptionHandler $exceptionHandler Fetch exception handler.
4748
*/
48-
public function setExceptionHandler(callable $exceptionHandler)
49+
public function setExceptionHandler(FetchExceptionHandler $exceptionHandler)
4950
{
5051
$this->context->setResourceFetchExceptionHandler($exceptionHandler);
5152
}

src/Specification/ImportSpecification.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ImportSpecification
4444
private $maxFetchAttempts = self::DEFAULT_FETCH_ATTEMPTS;
4545

4646
/**
47-
* @var callable
47+
* @var FetchExceptionHandler
4848
*/
4949
private $fetchExceptionHandler;
5050

@@ -68,7 +68,7 @@ function (Transformer $transformer) {
6868
));
6969

7070
is_object($this->context) && $this->context = clone $this->context;
71-
is_object($this->fetchExceptionHandler) && $this->fetchExceptionHandler = clone $this->fetchExceptionHandler;
71+
$this->fetchExceptionHandler && $this->fetchExceptionHandler = clone $this->fetchExceptionHandler;
7272
}
7373

7474
/**

test/Integration/Porter/Connector/ConnectionContextTest.php

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
namespace ScriptFUSIONTest\Integration\Porter\Connector;
33

44
use ScriptFUSION\Porter\Connector\ConnectionContext;
5+
use ScriptFUSION\Porter\Connector\FetchExceptionHandler\StatelessFetchExceptionHandler;
56
use ScriptFUSION\Porter\Connector\RecoverableConnectorException;
67
use ScriptFUSIONTest\FixtureFactory;
78
use ScriptFUSIONTest\Stubs\TestFetchExceptionHandler;
89

10+
/**
11+
* @see ConnectionContext
12+
*/
913
final class ConnectionContextTest extends \PHPUnit_Framework_TestCase
1014
{
1115
/**
@@ -20,13 +24,7 @@ public function testFetchExceptionHandlerCloned(TestFetchExceptionHandler $handl
2024
$handler->initialize();
2125
$initial = $handler->getCurrent();
2226

23-
$context->retry(static function () {
24-
static $invocationCount;
25-
26-
if (!$invocationCount++) {
27-
throw new RecoverableConnectorException;
28-
}
29-
});
27+
$context->retry(self::createExceptionThrowingClosure());
3028

3129
self::assertSame($initial, $handler->getCurrent());
3230
}
@@ -43,4 +41,49 @@ public function provideHandlerAndContext()
4341
$context->setResourceFetchExceptionHandler($handler);
4442
yield 'Resource exception handler' => [$handler, $context];
4543
}
44+
45+
/**
46+
* Tests that when retry() is called, a stateless fetch exception handler is neither cloned nor reinitialized.
47+
* For stateless handlers, initialization is a NOOP, so avoiding cloning is a small optimization.
48+
*/
49+
public function testStatelessExceptionHandlerNotCloned()
50+
{
51+
$context = FixtureFactory::buildConnectionContext(
52+
false,
53+
$handler = new StatelessFetchExceptionHandler(static function () {
54+
// Intentionally empty.
55+
})
56+
);
57+
58+
$context->retry(self::createExceptionThrowingClosure());
59+
60+
self::assertSame(
61+
$handler,
62+
call_user_func(
63+
\Closure::bind(
64+
function () {
65+
return $this->fetchExceptionHandler;
66+
},
67+
$context,
68+
$context
69+
)
70+
)
71+
);
72+
}
73+
74+
/**
75+
* Creates a closure that only throws an exception on the first invocation.
76+
*
77+
* @return \Closure
78+
*/
79+
private static function createExceptionThrowingClosure()
80+
{
81+
return static function () {
82+
static $invocationCount;
83+
84+
if (!$invocationCount++) {
85+
throw new RecoverableConnectorException;
86+
}
87+
};
88+
}
4689
}

0 commit comments

Comments
 (0)