Skip to content

Commit 5c507e6

Browse files
committed
Container: detects circular reference for parameters
1 parent a4c7ed4 commit 5c507e6

File tree

3 files changed

+23
-14
lines changed

3 files changed

+23
-14
lines changed

src/DI/Container.php

+21-12
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ public function getParameters(): array
6363
public function getParameter($key)
6464
{
6565
if (!array_key_exists($key, $this->parameters)) {
66-
$this->parameters[$key] = $this->getDynamicParameter($key);
66+
$this->parameters[$key] = $this->preventDeadLock("%$key%", function () use ($key) {
67+
return $this->getDynamicParameter($key);
68+
});
6769
}
6870
return $this->parameters[$key];
6971
}
@@ -211,22 +213,15 @@ public function createService(string $name, array $args = []): object
211213
$name = $this->aliases[$name] ?? $name;
212214
$method = self::getMethodName($name);
213215
$cb = $this->methods[$method] ?? null;
214-
if (isset($this->creating[$name])) {
215-
throw new Nette\InvalidStateException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($this->creating))));
216-
217-
} elseif ($cb === null) {
216+
if ($cb === null) {
218217
throw new MissingServiceException(sprintf("Service '%s' not found.", $name));
219218
}
220219

221-
try {
222-
$this->creating[$name] = true;
223-
$service = $cb instanceof \Closure
220+
$service = $this->preventDeadLock($name, function () use ($cb, $args, $method) {
221+
return $cb instanceof \Closure
224222
? $cb(...$args)
225223
: $this->$method(...$args);
226-
227-
} finally {
228-
unset($this->creating[$name]);
229-
}
224+
});
230225

231226
if (!is_object($service)) {
232227
throw new Nette\UnexpectedValueException(sprintf(
@@ -317,6 +312,20 @@ public function findByTag(string $tag): array
317312
}
318313

319314

315+
private function preventDeadLock(string $key, \Closure $closure)
316+
{
317+
if (isset($this->creating[$key])) {
318+
throw new Nette\InvalidStateException(sprintf('Circular reference detected for: %s.', implode(', ', array_keys($this->creating))));
319+
}
320+
try {
321+
$this->creating[$key] = true;
322+
return $closure();
323+
} finally {
324+
unset($this->creating[$key]);
325+
}
326+
}
327+
328+
320329
/********************* autowiring ****************d*g**/
321330

322331

tests/DI/Compiler.parameters.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,6 @@ test('', function () {
133133
$container->getParameter('bar');
134134
},
135135
Nette\InvalidStateException::class,
136-
'Circular reference detected for services: one.'
136+
'Circular reference detected for: %bar%, one.'
137137
);
138138
});

tests/DI/Container.circular.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,4 @@ $container = new MyContainer;
3232

3333
Assert::exception(function () use ($container) {
3434
$container->getService('one');
35-
}, Nette\InvalidStateException::class, 'Circular reference detected for services: one, two.');
35+
}, Nette\InvalidStateException::class, 'Circular reference detected for: one, two.');

0 commit comments

Comments
 (0)