Skip to content
This repository was archived by the owner on Feb 6, 2020. It is now read-only.

Commit 2413112

Browse files
author
fhein
committed
Tests and fix for mapAliasesToTargets as of #221.
1 parent f0f2cd3 commit 2413112

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

src/ServiceManager.php

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,13 @@ private function mapAliasToTarget($alias, $target)
868868
*
869869
* This function maps $this->aliases in place.
870870
*
871-
* This algorithm is fast for mass updates through configure().
871+
* This algorithm is an adaptated version of Tarjans Strongly
872+
* Connected Components. Instead of returning the strongly
873+
* connected components (i.e. cycles in our case), we throw.
874+
* If nodes are not strongly connected (i.e. resolvable in
875+
* our case), they get resolved.
876+
*
877+
* This algorithm fast for mass updates through configure().
872878
* It is not appropriate if just a single alias is added.
873879
*
874880
* @see mapAliasToTarget above
@@ -881,17 +887,40 @@ private function mapAliasesToTargets()
881887
if (isset($tagged[$alias])) {
882888
continue;
883889
}
890+
884891
$tCursor = $this->aliases[$alias];
885892
$aCursor = $alias;
893+
if ($aCursor === $tCursor) {
894+
throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases);
895+
}
896+
if (! isset($this->aliases[$tCursor])) {
897+
continue;
898+
}
899+
886900
while (isset($this->aliases[$tCursor])) {
887-
$tagged[$aCursor] = true;
888-
$this->aliases[$aCursor] = $this->aliases[$tCursor];
901+
$stack[] = $aCursor;
902+
if ($aCursor === $this->aliases[$tCursor]) {
903+
throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases);
904+
}
889905
$aCursor = $tCursor;
890906
$tCursor = $this->aliases[$tCursor];
891-
if ($aCursor === $tCursor) {
907+
}
908+
909+
$tagged[$aCursor] = true;
910+
911+
if (! isset($stack)) {
912+
continue;
913+
}
914+
915+
foreach ($stack as $_ => $alias) {
916+
if ($alias === $tCursor) {
892917
throw CyclicAliasException::fromCyclicAlias($alias, $this->aliases);
893918
}
919+
$this->aliases[$alias] = $tCursor;
920+
$tagged[$alias] = true;
894921
}
922+
923+
unset($stack);
895924
}
896925
}
897926

test/CommonServiceLocatorBehaviorsTrait.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,28 @@ public function testCrashesOnCyclicAliases()
855855
],
856856
]);
857857
}
858+
859+
public function testMinimalCyclicAliasDefinitionShouldThrow()
860+
{
861+
$sm = $this->createContainer([]);
862+
863+
$this->expectException(CyclicAliasException::class);
864+
$sm->setAlias('alias', 'alias');
865+
}
866+
867+
public function testCoverageDepthFirstTaggingOnRecursiveAliasDefinitions()
868+
{
869+
$sm = $this->createContainer([
870+
'factories' => [
871+
stdClass::class => InvokableFactory::class,
872+
],
873+
'aliases' => [
874+
'alias1' => 'alias2',
875+
'alias2' => 'alias3',
876+
'alias3' => stdClass::class,
877+
],
878+
]);
879+
$this->assertSame($sm->get('alias1'), $sm->get('alias2'));
880+
$this->assertSame($sm->get(stdClass::class), $sm->get('alias1'));
881+
}
858882
}

0 commit comments

Comments
 (0)