Skip to content

Commit f740a01

Browse files
authored
Merge pull request #64172 from nextcloud/perf/short-circuit-aliases
perf: Speed up fetching services from container
2 parents fd847a4 + daf9fb8 commit f740a01

4 files changed

Lines changed: 34 additions & 41 deletions

File tree

‎lib/private/AppFramework/DependencyInjection/DIContainer.php‎

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -309,27 +309,16 @@ public function has($id): bool {
309309
*/
310310
#[\Override]
311311
protected function query(string $name, bool $autoload = true, array $chain = []): mixed {
312+
$name = $this->resolveAlias($name);
312313
if ($name === 'AppName' || $name === 'appName') {
313314
return $this->appName;
314315
}
315316

316-
$isServerClass = str_starts_with($name, 'OCP\\') || str_starts_with($name, 'OC\\');
317-
if ($isServerClass && !$this->has($name)) {
318-
return $this->server->query($name, $autoload, $chain);
319-
}
320-
321-
try {
322-
return $this->queryNoFallback($name, $chain);
323-
} catch (QueryException $firstException) {
324-
try {
325-
return $this->server->query($name, $autoload, $chain);
326-
} catch (QueryException $secondException) {
327-
if ($firstException->getCode() === 1) {
328-
throw $secondException;
329-
}
330-
throw $firstException;
331-
}
317+
$result = $this->queryNoFallback($name, $chain);
318+
if ($result !== null) {
319+
return $result;
332320
}
321+
return $this->server->query($name, $autoload, $chain);
333322
}
334323

335324
/**
@@ -340,6 +329,7 @@ protected function query(string $name, bool $autoload = true, array $chain = [])
340329
* @internal
341330
*/
342331
public function queryNoFallback($name, array $chain) {
332+
$name = $this->resolveAlias($name);
343333
if (isset($this->container[$name])) {
344334
return $this->container[$name];
345335
} elseif ($this->appName === 'settings' && str_starts_with($name, 'OC\\Settings\\')) {
@@ -353,8 +343,6 @@ public function queryNoFallback($name, array $chain) {
353343
/* AppFramework services are scoped to the application */
354344
return parent::query($name, chain: $chain);
355345
}
356-
357-
throw new QueryException('Could not resolve ' . $name . '!'
358-
. ' Class can not be instantiated', 1);
346+
return null;
359347
}
360348
}

‎lib/private/AppFramework/Utility/SimpleContainer.php‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
3232

3333
protected Container $container;
3434

35+
/** @var array<string,string> */
36+
private array $aliases = [];
37+
3538
public function __construct() {
3639
$this->container = new Container();
3740
}
@@ -49,7 +52,7 @@ public function get(string $id): mixed {
4952
#[\Override]
5053
public function has(string $id): bool {
5154
// If a service is no registered but is an existing class, we can probably load it
52-
return isset($this->container[$id]) || class_exists($id);
55+
return isset($this->aliases[$id]) || isset($this->container[$id]) || class_exists($id);
5356
}
5457

5558
/**
@@ -152,6 +155,7 @@ public function resolve(string $name, array $chain = []): mixed {
152155
* @param list<class-string> $chain
153156
*/
154157
protected function query(string $name, bool $autoload = true, array $chain = []): mixed {
158+
$name = $this->resolveAlias($name);
155159
if (isset($this->container[$name])) {
156160
return $this->container[$name];
157161
}
@@ -195,6 +199,9 @@ public function registerService(string $name, Closure $closure, bool $shared = t
195199
if (isset($this->container[$name])) {
196200
unset($this->container[$name]);
197201
}
202+
if (isset($this->aliases[$name])) {
203+
unset($this->aliases[$name]);
204+
}
198205
if ($shared) {
199206
$this->container[$name] = $wrapped;
200207
} else {
@@ -210,11 +217,14 @@ public function registerService(string $name, Closure $closure, bool $shared = t
210217
* @param string $target the target that should be resolved instead
211218
*/
212219
public function registerAlias(string $alias, string $target): void {
213-
$this->registerService(
214-
$alias,
215-
static fn (ContainerInterface $container): mixed => $container->get($target),
216-
false,
217-
);
220+
$this->aliases[$alias] = $target;
221+
}
222+
223+
protected function resolveAlias(string $name) : string {
224+
while (isset($this->aliases[$name])) {
225+
$name = $this->aliases[$name];
226+
}
227+
return $name;
218228
}
219229

220230
protected function registerDeprecatedAlias(string $alias, string $target): void {

‎lib/private/ServerContainer.php‎

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,16 @@ public function has($id, bool $noRecursion = false): bool {
123123
*/
124124
#[\Override]
125125
protected function query(string $name, bool $autoload = true, array $chain = []): mixed {
126+
$name = $this->resolveAlias($name);
126127
if (str_starts_with($name, 'OCA\\')) {
127-
// Skip server container query for app namespace classes
128-
if (isset($this->container[$name])) {
129-
return $this->container[$name];
130-
}
131-
// Continue with general autoloading
132-
// In case the service starts with OCA\ we try to find the service in
133-
// the apps container first.
128+
// In case the service starts with OCA\ we try to find the service in the apps container.
134129
if (($appContainer = $this->getAppContainerForService($name)) !== null) {
135-
try {
136-
return $appContainer->queryNoFallback($name, $chain);
137-
} catch (QueryException $e) {
138-
// Didn't find the service or the respective app container
139-
// In this case the service won't be part of the core container,
140-
// so we can throw directly
141-
throw $e;
130+
$result = $appContainer->queryNoFallback($name, $chain);
131+
if ($result !== null) {
132+
return $result;
142133
}
134+
throw new QueryException('Could not resolve ' . $name . '!'
135+
. ' Class can not be instantiated', 1);
143136
}
144137
}
145138

‎tests/lib/Settings/DeclarativeManagerTest.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,8 @@ public function testSetValueWithHandler(): void {
583583
->method('setValue')
584584
->with('test_field_2', 'some password', $this->adminUser);
585585

586-
\OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
586+
$appContainer = \OC::$server->getAppContainerForService('OCA\\Testing\\Settings\\DeclarativeForm');
587+
$appContainer->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
587588

588589
$context = $this->createMock(RegistrationContext::class);
589590
$context->expects(self::atLeastOnce())
@@ -616,7 +617,8 @@ public function testGetValueWithHandler(): void {
616617
->with('test_field_2', $this->adminUser)
617618
->willReturn('very secret password');
618619

619-
\OC::$server->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
620+
$appContainer = \OC::$server->getAppContainerForService('OCA\\Testing\\Settings\\DeclarativeForm');
621+
$appContainer->registerService('OCA\\Testing\\Settings\\DeclarativeForm', fn () => $form, false);
620622

621623
$context = $this->createMock(RegistrationContext::class);
622624
$context->expects(self::atLeastOnce())

0 commit comments

Comments
 (0)