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

Commit 5f3bb42

Browse files
committed
Merge branch 'feature/#112-#113-improve-set-alias-and-set-factory-performance' into develop
Close #113
2 parents 2aec46d + 7520428 commit 5f3bb42

File tree

4 files changed

+158
-5
lines changed

4 files changed

+158
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ All notable changes to this project will be documented in this file, in reverse
1111
`zendframework/zend-servicemanager`.
1212
- [#103](https://github.com/zendframework/zend-servicemanager/pull/103) Disallowing
1313
test failures when running tests against PHP `7.0.*`.
14+
- [#103](https://github.com/zendframework/zend-servicemanager/pull/103) Improved performance
15+
when dealing with registering aliases and factories via `ServiceManager#setFactory()` and
16+
`ServiceManager#setAlias()`
1417

1518
### Deprecated
1619

benchmarks/SetNewServicesBench.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace ZendBench\ServiceManager;
4+
5+
use PhpBench\Benchmark\Metadata\Annotations\Iterations;
6+
use PhpBench\Benchmark\Metadata\Annotations\Revs;
7+
use PhpBench\Benchmark\Metadata\Annotations\Warmup;
8+
use Zend\ServiceManager\ServiceManager;
9+
10+
/**
11+
* @Revs(1000)
12+
* @Iterations(10)
13+
* @Warmup(2)
14+
*/
15+
class SetNewServicesBench
16+
{
17+
const NUM_SERVICES = 100;
18+
19+
/**
20+
* @var ServiceManager
21+
*/
22+
private $sm;
23+
24+
public function __construct()
25+
{
26+
$config = [
27+
'factories' => [
28+
'factory1' => BenchAsset\FactoryFoo::class,
29+
],
30+
'invokables' => [
31+
'invokable1' => BenchAsset\Foo::class,
32+
],
33+
'services' => [
34+
'service1' => new \stdClass(),
35+
],
36+
'aliases' => [
37+
'factoryAlias1' => 'factory1',
38+
'recursiveFactoryAlias1' => 'factoryAlias1',
39+
'recursiveFactoryAlias2' => 'recursiveFactoryAlias1',
40+
],
41+
'abstract_factories' => [
42+
BenchAsset\AbstractFactoryFoo::class
43+
],
44+
];
45+
46+
for ($i = 0; $i <= self::NUM_SERVICES; $i++) {
47+
$config['factories']["factory_$i"] = BenchAsset\FactoryFoo::class;
48+
$config['aliases']["alias_$i"] = "service_$i";
49+
}
50+
51+
$this->sm = new ServiceManager($config);
52+
}
53+
54+
public function benchSetFactory()
55+
{
56+
// @todo @link https://github.com/phpbench/phpbench/issues/304
57+
$sm = clone $this->sm;
58+
59+
$sm->setFactory('factory2', BenchAsset\FactoryFoo::class);
60+
}
61+
62+
public function benchSetAlias()
63+
{
64+
// @todo @link https://github.com/phpbench/phpbench/issues/304
65+
$sm = clone $this->sm;
66+
67+
$sm->setAlias('factoryAlias2', 'factory1');
68+
}
69+
70+
public function benchSetAliasOverrided()
71+
{
72+
// @todo @link https://github.com/phpbench/phpbench/issues/304
73+
$sm = clone $this->sm;
74+
75+
$sm->setAlias('recursiveFactoryAlias1', 'factory1');
76+
}
77+
}

src/ServiceManager.php

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,8 @@ public function configure(array $config)
343343
}
344344

345345
if (isset($config['aliases'])) {
346-
$this->aliases = $config['aliases'] + $this->aliases;
347-
}
348-
349-
if (! empty($this->aliases)) {
346+
$this->configureAliases($config['aliases']);
347+
} elseif (! $this->configured && ! empty($this->aliases)) {
350348
$this->resolveAliases($this->aliases);
351349
}
352350

@@ -376,6 +374,35 @@ public function configure(array $config)
376374
return $this;
377375
}
378376

377+
/**
378+
* @param string[] $aliases
379+
*
380+
* @return void
381+
*/
382+
private function configureAliases(array $aliases)
383+
{
384+
if (! $this->configured) {
385+
$this->aliases = $aliases + $this->aliases;
386+
387+
$this->resolveAliases($this->aliases);
388+
389+
return;
390+
}
391+
392+
// Performance optimization. If there are no collisions, then we don't need to recompute loops
393+
$intersecting = $this->aliases && \array_intersect_key($this->aliases, $aliases);
394+
$this->aliases = $this->aliases ? \array_merge($this->aliases, $aliases) : $aliases;
395+
396+
if ($intersecting) {
397+
$this->resolveAliases($this->aliases);
398+
399+
return;
400+
}
401+
402+
$this->resolveAliases($aliases);
403+
$this->resolveNewAliasesWithPreviouslyResolvedAliases($aliases);
404+
}
405+
379406
/**
380407
* Add an alias.
381408
*
@@ -570,7 +597,11 @@ private function resolveInitializers(array $initializers)
570597
}
571598

572599
/**
573-
* Resolve all aliases to their canonical service names.
600+
* Resolve aliases to their canonical service names.
601+
*
602+
* @param string[] $aliases
603+
*
604+
* @returns void
574605
*/
575606
private function resolveAliases(array $aliases)
576607
{
@@ -591,6 +622,23 @@ private function resolveAliases(array $aliases)
591622
}
592623
}
593624

625+
/**
626+
* Rewrites the map of aliases by resolving the given $aliases with the existing resolved ones.
627+
* This is mostly done for performance reasons.
628+
*
629+
* @param string[] $aliases
630+
*
631+
* @return void
632+
*/
633+
private function resolveNewAliasesWithPreviouslyResolvedAliases(array $aliases)
634+
{
635+
foreach ($this->resolvedAliases as $name => $target) {
636+
if (isset($aliases[$target])) {
637+
$this->resolvedAliases[$name] = $this->resolvedAliases[$target];
638+
}
639+
}
640+
}
641+
594642
/**
595643
* Get a factory for the given service name
596644
*

test/ServiceManagerTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,29 @@ public function testAliasToAnExplicitServiceShouldWork()
236236

237237
$this->assertSame($service, $alias);
238238
}
239+
240+
/**
241+
* @depends testAliasToAnExplicitServiceShouldWork
242+
*/
243+
public function testSetAliasShouldWorkWithRecursiveAlias()
244+
{
245+
$config = [
246+
'aliases' => [
247+
'Alias' => 'TailInvokable',
248+
],
249+
'services' => [
250+
InvokableObject::class => new InvokableObject(),
251+
],
252+
];
253+
$serviceManager = new ServiceManager($config);
254+
$serviceManager->setAlias('HeadAlias', 'Alias');
255+
$serviceManager->setAlias('TailInvokable', InvokableObject::class);
256+
257+
$service = $serviceManager->get(InvokableObject::class);
258+
$alias = $serviceManager->get('Alias');
259+
$headAlias = $serviceManager->get('HeadAlias');
260+
261+
$this->assertSame($service, $alias);
262+
$this->assertSame($service, $headAlias);
263+
}
239264
}

0 commit comments

Comments
 (0)