Skip to content

Commit e562037

Browse files
authored
Merge pull request #43 from bigcommerce/perf/constructor-signature-caching
Cache constructor signatures in serviceCache
2 parents ba488a6 + bec315e commit e562037

4 files changed

Lines changed: 44 additions & 7 deletions

File tree

.phpstan/baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ parameters:
3030
count: 1
3131
path: ../src/Injector.php
3232

33-
-
34-
message: '#^Method Bigcommerce\\Injector\\Injector\:\:buildParameterArray\(\) has InvalidArgumentException in PHPDoc @throws tag but it''s not thrown\.$#'
35-
identifier: throws.unusedType
36-
count: 1
37-
path: ../src/Injector.php
38-
3933
-
4034
message: '#^Method Bigcommerce\\Injector\\Injector\:\:buildParameterArray\(\) has parameter \$methodSignature with no value type specified in iterable type array\.$#'
4135
identifier: missingType.iterableValue

src/Injector.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ public function canAutoCreate($className): bool
198198
* @return array
199199
* @throws InjectorInvocationException
200200
* @throws MissingRequiredParameterException
201-
* @throws InvalidArgumentException
202201
* @throws ReflectionException
203202
*/
204203
private function buildParameterArray($methodSignature, $providedParameters)

src/Reflection/CachingClassInspector.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,19 @@ public function getCallableConstructorSignature(string $class): array|false|null
109109
if (isset($this->constructorCache[$class])) {
110110
return $this->constructorCache[$class][0];
111111
}
112+
113+
$key = "$class::__construct::callable_signature";
114+
if ($this->serviceCache->has($key)) {
115+
$result = $this->serviceCache->get($key);
116+
$this->constructorCache[$class] = [$result];
117+
return $result;
118+
}
119+
112120
$result = $this->classInspector->getCallableConstructorSignature($class);
113121
$this->constructorCache[$class] = [$result];
122+
if (is_array($result)) {
123+
$this->serviceCache->set($key, $result);
124+
}
114125
return $result;
115126
}
116127

tests/Reflection/CachingClassInspectorTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected function setUp(): void
2929
$serviceCache = $this->prophesize(ServiceCacheInterface::class);
3030
$serviceCache->set(Argument::cetera())->will(function ($arguments) use ($serviceCache) {
3131
$serviceCache->get($arguments[0])->willReturn($arguments[1]);
32+
$serviceCache->has($arguments[0])->willReturn(true);
3233
});
3334
$this->serviceCache = $serviceCache;
3435
$this->classInspector = $this->prophesize(ClassInspector::class);
@@ -58,6 +59,7 @@ public function testWarmCachePopulatesCachesForNonConstructorMethod(): void
5859
public function testWarmCacheUsesOptimizedPathForConstructor(): void
5960
{
6061
$signature = [['name' => 'dependency', 'type' => 'SomeClass']];
62+
$this->serviceCache->has(Argument::cetera())->willReturn(false);
6163
$this->classInspector->getCallableConstructorSignature(DummyDependency::class)
6264
->willReturn($signature);
6365

@@ -68,9 +70,25 @@ public function testWarmCacheUsesOptimizedPathForConstructor(): void
6870
$this->classInspector->getMethodSignature(Argument::cetera())->shouldNotHaveBeenCalled();
6971
}
7072

73+
public function testWarmCachePopulatesServiceCacheForConstructor(): void
74+
{
75+
$signature = [['name' => 'dependency', 'type' => 'SomeClass']];
76+
$this->serviceCache->has(Argument::cetera())->willReturn(false);
77+
$this->classInspector->getCallableConstructorSignature(DummyDependency::class)
78+
->willReturn($signature);
79+
80+
$this->subject->warmCache(DummyDependency::class, '__construct');
81+
82+
$this->serviceCache->set(
83+
"Tests\Dummy\DummyDependency::__construct::callable_signature",
84+
$signature
85+
)->shouldHaveBeenCalled();
86+
}
87+
7188
public function testGetCallableConstructorSignatureCachesResult(): void
7289
{
7390
$signature = [['name' => 'dependency', 'type' => 'SomeClass']];
91+
$this->serviceCache->has(Argument::cetera())->willReturn(false);
7492
$this->classInspector->getCallableConstructorSignature(DummyDependency::class)
7593
->willReturn($signature)
7694
->shouldBeCalledOnce();
@@ -82,8 +100,22 @@ public function testGetCallableConstructorSignatureCachesResult(): void
82100
$this->assertEquals($signature, $result2);
83101
}
84102

103+
public function testGetCallableConstructorSignatureUsesServiceCacheOnL1Miss(): void
104+
{
105+
$signature = [['name' => 'dependency', 'type' => 'SomeClass']];
106+
$key = "Tests\Dummy\DummyDependency::__construct::callable_signature";
107+
$this->serviceCache->has($key)->willReturn(true);
108+
$this->serviceCache->get($key)->willReturn($signature);
109+
110+
$result = $this->subject->getCallableConstructorSignature(DummyDependency::class);
111+
112+
$this->assertEquals($signature, $result);
113+
$this->classInspector->getCallableConstructorSignature(Argument::cetera())->shouldNotHaveBeenCalled();
114+
}
115+
85116
public function testGetCallableConstructorSignatureReturnsNullForNoConstructor(): void
86117
{
118+
$this->serviceCache->has(Argument::cetera())->willReturn(false);
87119
$this->classInspector->getCallableConstructorSignature(DummyDependency::class)
88120
->willReturn(null);
89121

@@ -94,6 +126,7 @@ public function testGetCallableConstructorSignatureReturnsNullForNoConstructor()
94126

95127
public function testGetCallableConstructorSignatureReturnsFalseForNonPublicConstructor(): void
96128
{
129+
$this->serviceCache->has(Argument::cetera())->willReturn(false);
97130
$this->classInspector->getCallableConstructorSignature(DummyDependency::class)
98131
->willReturn(false);
99132

0 commit comments

Comments
 (0)