minor #14643 [DependencyInjection] Avoid unnecessary calls to strtolower() (nicolas-grekas)

This PR was merged into the 2.3 branch.

Discussion
----------

[DependencyInjection] Avoid unnecessary calls to strtolower()

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #14558
| License       | MIT
| Doc PR        | -

Commits
-------

c27f564 [DependencyInjection] Avoid unnecessary calls to strtolower()
This commit is contained in:
Fabien Potencier 2015-05-28 16:28:38 +02:00
commit 41adf224b5
2 changed files with 63 additions and 58 deletions

View File

@ -76,6 +76,8 @@ class Container implements IntrospectableContainerInterface
protected $scopeStacks; protected $scopeStacks;
protected $loading = array(); protected $loading = array();
private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
/** /**
* Constructor. * Constructor.
* *
@ -218,7 +220,7 @@ class Container implements IntrospectableContainerInterface
$this->services[$id] = $service; $this->services[$id] = $service;
if (method_exists($this, $method = 'synchronize'.strtr($id, array('_' => '', '.' => '_', '\\' => '_')).'Service')) { if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) {
$this->$method(); $this->$method();
} }
@ -242,17 +244,20 @@ class Container implements IntrospectableContainerInterface
*/ */
public function has($id) public function has($id)
{ {
$id = strtolower($id); for ($i = 2;;) {
if ('service_container' === $id
if ('service_container' === $id) { || isset($this->aliases[$id])
return true; || isset($this->services[$id])
|| array_key_exists($id, $this->services)
) {
return true;
}
if (--$i && $id !== $lcId = strtolower($id)) {
$id = $lcId;
} else {
return method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service');
}
} }
return isset($this->services[$id])
|| array_key_exists($id, $this->services)
|| isset($this->aliases[$id])
|| method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_', '\\' => '_')).'Service')
;
} }
/** /**
@ -280,10 +285,7 @@ class Container implements IntrospectableContainerInterface
// available services. Service IDs are case insensitive, however since // available services. Service IDs are case insensitive, however since
// this method can be called thousands of times during a request, avoid // this method can be called thousands of times during a request, avoid
// calling strtolower() unless necessary. // calling strtolower() unless necessary.
foreach (array(false, true) as $strtolower) { for ($i = 2;;) {
if ($strtolower) {
$id = strtolower($id);
}
if ('service_container' === $id) { if ('service_container' === $id) {
return $this; return $this;
} }
@ -294,57 +296,60 @@ class Container implements IntrospectableContainerInterface
if (isset($this->services[$id]) || array_key_exists($id, $this->services)) { if (isset($this->services[$id]) || array_key_exists($id, $this->services)) {
return $this->services[$id]; return $this->services[$id];
} }
}
if (isset($this->loading[$id])) { if (isset($this->loading[$id])) {
throw new ServiceCircularReferenceException($id, array_keys($this->loading)); throw new ServiceCircularReferenceException($id, array_keys($this->loading));
} }
if (isset($this->methodMap[$id])) { if (isset($this->methodMap[$id])) {
$method = $this->methodMap[$id]; $method = $this->methodMap[$id];
} elseif (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_', '\\' => '_')).'Service')) { } elseif (--$i && $id !== $lcId = strtolower($id)) {
// $method is set to the right value, proceed $id = $lcId;
} else { continue;
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) { } elseif (method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) {
if (!$id) { // $method is set to the right value, proceed
throw new ServiceNotFoundException($id); } else {
} if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
if (!$id) {
$alternatives = array(); throw new ServiceNotFoundException($id);
foreach ($this->services as $key => $associatedService) {
$lev = levenshtein($id, $key);
if ($lev <= strlen($id) / 3 || false !== strpos($key, $id)) {
$alternatives[] = $key;
} }
$alternatives = array();
foreach ($this->services as $key => $associatedService) {
$lev = levenshtein($id, $key);
if ($lev <= strlen($id) / 3 || false !== strpos($key, $id)) {
$alternatives[] = $key;
}
}
throw new ServiceNotFoundException($id, null, null, $alternatives);
} }
throw new ServiceNotFoundException($id, null, null, $alternatives);
}
return;
}
$this->loading[$id] = true;
try {
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
if (array_key_exists($id, $this->services)) {
unset($this->services[$id]);
}
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return; return;
} }
throw $e; $this->loading[$id] = true;
try {
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
if (array_key_exists($id, $this->services)) {
unset($this->services[$id]);
}
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
}
throw $e;
}
unset($this->loading[$id]);
return $service;
} }
unset($this->loading[$id]);
return $service;
} }
/** /**

View File

@ -289,7 +289,7 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$container->enterScope('foo'); $container->enterScope('foo');
$scoped2 = $container->get('scoped'); $scoped2 = $container->get('scoped');
$scoped3 = $container->get('scoped'); $scoped3 = $container->get('SCOPED');
$scopedFoo2 = $container->get('scoped_foo'); $scopedFoo2 = $container->get('scoped_foo');
$container->leaveScope('foo'); $container->leaveScope('foo');