Skip to content

Commit e112dd2

Browse files
Merge pull request #102 from Xerkus/hotfix/recursive-performance-drop
Extract recursive method from ConfigPostProcessor::__invoke() to avoid performance hit
2 parents d74d2da + 07d4ce7 commit e112dd2

File tree

2 files changed

+64
-58
lines changed

2 files changed

+64
-58
lines changed

psalm-baseline.xml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="4.9.3@4c262932602b9bbab5020863d1eb22d49de0dbf4">
2+
<files psalm-version="4.21.0@d8bec4c7aaee111a532daec32fb09de5687053d1">
33
<file src="config/replacements.php">
44
<DuplicateArrayKey occurrences="3">
55
<code>'ZendAcl' =&gt; 'LaminasAcl'</code>
@@ -41,9 +41,7 @@
4141
<code>$newKey</code>
4242
<code>$target</code>
4343
</MixedArgument>
44-
<MixedArgumentTypeCoercion occurrences="1">
45-
<code>[$key]</code>
46-
</MixedArgumentTypeCoercion>
44+
<MixedArgumentTypeCoercion occurrences="1"/>
4745
<MixedArrayAssignment occurrences="4">
4846
<code>$config[$key]</code>
4947
<code>$config['aliases'][$alias]</code>
@@ -62,7 +60,7 @@
6260
<MixedArrayTypeCoercion occurrences="1">
6361
<code>$aliases[$name]</code>
6462
</MixedArrayTypeCoercion>
65-
<MixedAssignment occurrences="27">
63+
<MixedAssignment occurrences="26">
6664
<code>$a[$key]</code>
6765
<code>$a[$key]</code>
6866
<code>$a[]</code>
@@ -78,7 +76,6 @@
7876
<code>$key</code>
7977
<code>$name</code>
8078
<code>$newKey</code>
81-
<code>$newValue</code>
8279
<code>$notIn[]</code>
8380
<code>$result</code>
8481
<code>$rewritten[$key]</code>

src/ConfigPostProcessor.php

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,17 @@ class ConfigPostProcessor
2929
'zf-apigility' => 'api-tools',
3030
];
3131

32-
/** @var Replacements */
32+
/**
33+
* @psalm-suppress PropertyNotSetInConstructor Initialized during call to the only public method __invoke()
34+
* @var Replacements
35+
*/
3336
private $replacements;
3437

3538
/** @var callable[] */
3639
private $rulesets;
3740

3841
public function __construct()
3942
{
40-
// This value will be reset during __invoke(); setting here to prevent Psalm errors.
41-
$this->replacements = new Replacements();
42-
4343
/* Define the rulesets for replacements.
4444
*
4545
* Each ruleset has the following signature:
@@ -86,7 +86,7 @@ function ($value) {
8686
// Array values
8787
function ($value, array $keys) {
8888
return $keys !== [] && is_array($value)
89-
? [$this, '__invoke']
89+
? [$this, 'processConfig']
9090
: null;
9191
},
9292
];
@@ -100,51 +100,7 @@ function ($value, array $keys) {
100100
public function __invoke(array $config, array $keys = [])
101101
{
102102
$this->replacements = $this->initializeReplacements($config);
103-
$rewritten = [];
104-
105-
foreach ($config as $key => $value) {
106-
// Do not rewrite configuration for the bridge
107-
if ($key === 'laminas-zendframework-bridge') {
108-
$rewritten[$key] = $value;
109-
continue;
110-
}
111-
112-
// Determine new key from replacements
113-
$newKey = is_string($key) ? $this->replace($key, $keys) : $key;
114-
115-
// Keep original values with original key, if the key has changed, but only at the top-level.
116-
if (empty($keys) && $newKey !== $key) {
117-
$rewritten[$key] = $value;
118-
}
119-
120-
// Perform value replacements, if any
121-
$newValue = $this->replace($value, $keys, $newKey);
122-
123-
// Key does not already exist and/or is not an array value
124-
if (! array_key_exists($newKey, $rewritten) || ! is_array($rewritten[$newKey])) {
125-
// Do not overwrite existing values with null values
126-
$rewritten[$newKey] = array_key_exists($newKey, $rewritten) && null === $newValue
127-
? $rewritten[$newKey]
128-
: $newValue;
129-
continue;
130-
}
131-
132-
// New value is null; nothing to do.
133-
if (null === $newValue) {
134-
continue;
135-
}
136-
137-
// Key already exists as an array value, but $value is not an array
138-
if (! is_array($newValue)) {
139-
$rewritten[$newKey][] = $newValue;
140-
continue;
141-
}
142-
143-
// Key already exists as an array value, and $value is also an array
144-
$rewritten[$newKey] = static::merge($rewritten[$newKey], $newValue);
145-
}
146-
147-
return $rewritten;
103+
return $this->processConfig($config, $keys);
148104
}
149105

150106
/**
@@ -270,7 +226,7 @@ private function replaceDependencyConfiguration(array $config)
270226
continue;
271227
}
272228

273-
$config[$key] = is_array($data) ? $this->__invoke($data, [$key]) : $data;
229+
$config[$key] = is_array($data) ? $this->processConfig($data, [$key]) : $data;
274230
}
275231

276232
return $config;
@@ -414,7 +370,7 @@ private function replaceDependencyServices(array $config)
414370
}
415371

416372
$replacedService = $this->replacements->replace($service);
417-
$serviceInstance = is_array($serviceInstance) ? $this->__invoke($serviceInstance) : $serviceInstance;
373+
$serviceInstance = is_array($serviceInstance) ? $this->processConfig($serviceInstance) : $serviceInstance;
418374

419375
$config['services'][$replacedService] = $serviceInstance;
420376

@@ -461,4 +417,57 @@ private function initializeReplacements(array $config): Replacements
461417

462418
return new Replacements($replacements);
463419
}
420+
421+
/**
422+
* @param string[] $keys Hierarchy of keys, for determining location in
423+
* nested configuration.
424+
*/
425+
private function processConfig(array $config, array $keys = []): array
426+
{
427+
$rewritten = [];
428+
429+
foreach ($config as $key => $value) {
430+
// Do not rewrite configuration for the bridge
431+
if ($key === 'laminas-zendframework-bridge') {
432+
$rewritten[$key] = $value;
433+
continue;
434+
}
435+
436+
// Determine new key from replacements
437+
$newKey = is_string($key) ? $this->replace($key, $keys) : $key;
438+
439+
// Keep original values with original key, if the key has changed, but only at the top-level.
440+
if (empty($keys) && $newKey !== $key) {
441+
$rewritten[$key] = $value;
442+
}
443+
444+
// Perform value replacements, if any
445+
$newValue = $this->replace($value, $keys, $newKey);
446+
447+
// Key does not already exist and/or is not an array value
448+
if (!array_key_exists($newKey, $rewritten) || !is_array($rewritten[$newKey])) {
449+
// Do not overwrite existing values with null values
450+
$rewritten[$newKey] = array_key_exists($newKey, $rewritten) && null === $newValue
451+
? $rewritten[$newKey]
452+
: $newValue;
453+
continue;
454+
}
455+
456+
// New value is null; nothing to do.
457+
if (null === $newValue) {
458+
continue;
459+
}
460+
461+
// Key already exists as an array value, but $value is not an array
462+
if (!is_array($newValue)) {
463+
$rewritten[$newKey][] = $newValue;
464+
continue;
465+
}
466+
467+
// Key already exists as an array value, and $value is also an array
468+
$rewritten[$newKey] = static::merge($rewritten[$newKey], $newValue);
469+
}
470+
471+
return $rewritten;
472+
}
464473
}

0 commit comments

Comments
 (0)