[DependencyInjection] optimized compiled containers

* removed the __call() method in Container: it means that now, there is only
   one way to get a service: via the get() method;

 * removed the $shared variable in the dumped Container classes (we now use
   the $services variable from the parent class directly -- this is where we
   have a performance improvement);

 * optimized the PHP Dumper output.
This commit is contained in:
Fabien Potencier 2010-11-23 22:43:09 +01:00
parent 5e150931c9
commit 60bbb8f380
21 changed files with 43 additions and 125 deletions

View File

@ -56,8 +56,8 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$bundleClass = null;
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
$bundleDirs = $this->container->get('kernel')->getBundleDirs();
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
if (strpos(get_class($bundle), $input->getArgument('bundle')) !== false) {
$tmp = dirname(str_replace('\\', '/', get_class($bundle)));
$namespace = str_replace('/', '\\', dirname($tmp));

View File

@ -88,7 +88,7 @@ abstract class DoctrineCommand extends Command
protected function runCommand($name, array $input = array())
{
$application = new Application($this->container->getKernelService());
$application = new Application($this->container->get('kernel'));
$arguments = array();
$arguments = array_merge(array($name), $input);
$input = new ArrayInput($arguments);

View File

@ -62,7 +62,7 @@ EOT
}
$entityGenerator = $this->getEntityGenerator();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
// retrieve the full bundle classname
$class = $bundle->getReflection()->getName();

View File

@ -60,7 +60,7 @@ EOT
throw new \InvalidArgumentException('The bundle name must end with Bundle. Example: "Bundle\MySampleBundle".');
}
$dirs = $this->container->getKernelService()->getBundleDirs();
$dirs = $this->container->get('kernel')->getBundleDirs();
$tmp = str_replace('\\', '/', $bundle);
$namespace = str_replace('/', '\\', dirname($tmp));

View File

@ -54,8 +54,8 @@ EOT
protected function execute(InputInterface $input, OutputInterface $output)
{
$bundleClass = null;
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
$bundleDirs = $this->container->get('kernel')->getBundleDirs();
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
if (strpos(get_class($bundle), $input->getArgument('bundle')) !== false) {
$tmp = dirname(str_replace('\\', '/', get_class($bundle)));
$namespace = str_replace('/', '\\', dirname($tmp));

View File

@ -67,8 +67,8 @@ EOT
$paths = is_array($dirOrFile) ? $dirOrFile : array($dirOrFile);
} else {
$paths = array();
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
$bundleDirs = $this->container->get('kernel')->getBundleDirs();
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
$tmp = dirname(str_replace('\\', '/', get_class($bundle)));
$namespace = str_replace('/', '\\', dirname($tmp));
$class = basename($tmp);

View File

@ -67,8 +67,8 @@ EOT
$paths = is_array($dirOrFile) ? $dirOrFile : array($dirOrFile);
} else {
$paths = array();
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
$bundleDirs = $this->container->get('kernel')->getBundleDirs();
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
$tmp = dirname(str_replace('\\', '/', get_class($bundle)));
$namespace = str_replace('/', '\\', dirname($tmp));
$class = basename($tmp);

View File

@ -75,7 +75,7 @@ class Client extends BaseClient
return false;
}
return $this->container->getProfilerService()->loadFromResponse($this->response);
return $this->container->get('profiler')->loadFromResponse($this->response);
}
/**

View File

@ -52,7 +52,7 @@ class AssetsInstallCommand extends Command
$filesystem = new Filesystem();
foreach ($this->container->getKernelService()->getBundles() as $bundle) {
foreach ($this->container->get('kernel')->getBundles() as $bundle) {
if (is_dir($originDir = $bundle->getPath().'/Resources/public')) {
$output->writeln(sprintf('Installing assets for <comment>%s\\%s</comment>', $bundle->getNamespacePrefix(), $bundle->getName()));

View File

@ -51,7 +51,7 @@ class InitBundleCommand extends Command
throw new \InvalidArgumentException('The namespace must end with Bundle.');
}
$dirs = $this->container->getKernelService()->getBundleDirs();
$dirs = $this->container->get('kernel')->getBundleDirs();
$tmp = str_replace('\\', '/', $namespace);
$namespace = str_replace('/', '\\', dirname($tmp));

View File

@ -96,7 +96,7 @@ class ControllerResolver extends BaseControllerResolver
public function forward($controller, array $attributes = array(), array $query = array())
{
$attributes['_controller'] = $controller;
$subRequest = $this->container->getRequestService()->duplicate($query, null, $attributes);
$subRequest = $this->container->get('request')->duplicate($query, null, $attributes);
return $this->container->get('kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
@ -137,7 +137,7 @@ class ControllerResolver extends BaseControllerResolver
}
if (null === $this->esiSupport) {
$this->esiSupport = $this->container->has('esi') && $this->container->getEsiService()->hasSurrogateEsiCapability($this->container->getRequestService());
$this->esiSupport = $this->container->has('esi') && $this->container->get('esi')->hasSurrogateEsiCapability($this->container->get('request'));
}
if ($this->esiSupport && $options['standalone']) {
@ -148,10 +148,10 @@ class ControllerResolver extends BaseControllerResolver
$alt = $this->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
}
return $this->container->getEsiService()->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
return $this->container->get('esi')->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
}
$request = $this->container->getRequestService();
$request = $this->container->get('request');
// controller or URI?
if (0 === strpos($controller, '/')) {
@ -164,7 +164,7 @@ class ControllerResolver extends BaseControllerResolver
}
try {
$response = $this->container->getKernelService()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
$response = $this->container->get('kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);
if (200 != $response->getStatusCode()) {
throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode()));
@ -204,10 +204,10 @@ class ControllerResolver extends BaseControllerResolver
return $controller;
}
$uri = $this->container->getRouterService()->generate('_internal', array(
$uri = $this->container->get('router')->generate('_internal', array(
'controller' => $controller,
'path' => $attributes ? http_build_query($attributes) : 'none',
'_format' => $this->container->getRequestService()->getRequestFormat(),
'_format' => $this->container->get('request')->getRequestFormat(),
), true);
if ($query) {

View File

@ -39,7 +39,7 @@ abstract class WebTestCase extends BaseWebTestCase
$this->kernel = $this->createKernel($options);
$this->kernel->boot();
$client = $this->kernel->getContainer()->getTest_ClientService();
$client = $this->kernel->getContainer()->get('test.client');
$client->setServerParameters($server);
return $client;

View File

@ -181,9 +181,7 @@ class Container implements ContainerInterface
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
{
if (!is_string($id)) {
throw new \InvalidArgumentException(sprintf('A service id should be a string (%s given).', str_replace("\n", '', var_export($id, true))));
}
$id = (string) $id;
if (isset($this->services[$id])) {
return $this->services[$id];
@ -216,25 +214,6 @@ class Container implements ContainerInterface
return array_merge($ids, array_keys($this->services));
}
/**
* Catches unknown methods.
*
* @param string $method The called method name
* @param array $arguments The method arguments
*
* @return mixed
*
* @throws \BadMethodCallException When calling to an undefined method
*/
public function __call($method, $arguments)
{
if (!preg_match('/^get(.+)Service$/', $method, $match)) {
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
}
return $this->get(self::underscore($match[1]));
}
static public function camelize($id)
{
return preg_replace(array('/(?:^|_)+(.)/e', '/\.(.)/e'), array("strtoupper('\\1')", "'_'.strtoupper('\\1')"), $id);

View File

@ -60,17 +60,6 @@ class PhpDumper extends Dumper
}
}
protected function addServiceShared($id, $definition)
{
if ($definition->isShared()) {
return <<<EOF
if (isset(\$this->shared['$id'])) return \$this->shared['$id'];
EOF;
}
}
protected function addServiceReturn($id, $definition)
{
return <<<EOF
@ -94,20 +83,22 @@ EOF;
$arguments[] = $this->dumpValue($value);
}
if (null !== $definition->getFactoryMethod()) {
if (null !== $definition->getFactoryService()) {
$code = sprintf(" \$instance = %s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
} else {
$code = sprintf(" \$instance = call_user_func(array(%s, '%s')%s);\n", $class, $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
}
} elseif ($class != "'".str_replace('\\', '\\\\', $definition->getClass())."'") {
$code = sprintf(" \$class = %s;\n \$instance = new \$class(%s);\n", $class, implode(', ', $arguments));
if ($definition->isShared()) {
$instantiation = sprintf(" \$this->services['$id'] = \$instance");
} else {
$code = sprintf(" \$instance = new %s(%s);\n", $definition->getClass(), implode(', ', $arguments));
$instantiation = sprintf(" \$instance");
}
if ($definition->isShared()) {
$code .= sprintf(" \$this->shared['$id'] = \$instance;\n");
if (null !== $definition->getFactoryMethod()) {
if (null !== $definition->getFactoryService()) {
$code = sprintf("$instantiation = %s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
} else {
$code = sprintf("$instantiation = call_user_func(array(%s, '%s')%s);\n", $class, $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
}
} elseif (false !== strpos($class, '$')) {
$code = sprintf(" \$class = %s;\n$instantiation = new \$class(%s);\n", $class, implode(', ', $arguments));
} else {
$code = sprintf("$instantiation = new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
}
return $code;
@ -180,7 +171,6 @@ EOF;
$code .=
$this->addServiceInclude($id, $definition).
$this->addServiceShared($id, $definition).
$this->addServiceInstance($id, $definition).
$this->addServiceMethodCalls($id, $definition).
$this->addServiceConfigurator($id, $definition).
@ -284,8 +274,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\\$bagClass;
*/
class $class extends $baseClass implements TaggedContainerInterface
{
protected \$shared = array();
EOF;
}

View File

@ -178,7 +178,7 @@ abstract class Kernel implements HttpKernelInterface, \Serializable
$this->boot();
}
return $this->container->getHttpKernelService()->handle($request, $type, $catch);
return $this->container->get('http_kernel')->handle($request, $type, $catch);
}
/**

View File

@ -99,24 +99,6 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array('bar', 'foo_bar', 'foo.baz', 'service_container'), $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods');
}
/**
* @covers Symfony\Component\DependencyInjection\Container::__call
*/
public function testGetCall()
{
$sc = new Container();
$sc->set('foo_bar.foo', $foo = new \stdClass());
$this->assertEquals($foo, $sc->getFooBar_FooService(), '__call() finds services is the method is getXXXService()');
try {
$sc->getFooBar_Foo();
$this->fail('__call() throws a \BadMethodCallException exception if the method is not a service method');
} catch (\Exception $e) {
$this->assertInstanceOf('\BadMethodCallException', $e, '__call() throws a \BadMethodCallException exception if the method is not a service method');
$this->assertEquals('Call to undefined method Symfony\Component\DependencyInjection\Container::getFooBar_Foo.', $e->getMessage(), '__call() throws a \BadMethodCallException exception if the method is not a service method');
}
}
/**
* @covers Symfony\Component\DependencyInjection\Container::set
*/
@ -142,13 +124,6 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
$sc->set('bar', $bar = new \stdClass());
$this->assertSame($sc->get('bar'), $bar, '->getServiceIds() prefers to return a service defined with a getXXXService() method than one defined with set()');
try {
$sc->get(new \stdClass());
$this->fail('->get() throws a \InvalidArgumentException exception if the service id is not a string');
} catch (\Exception $e) {
$this->assertInstanceOf('\InvalidArgumentException', $e, '->get() throws a \InvalidArgumentException exception if the service id is not a string');
}
try {
$sc->get('');
$this->fail('->get() throws a \InvalidArgumentException exception if the service is empty');

View File

@ -77,7 +77,6 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$container->set('bar', $bar = new \stdClass());
$container->setParameter('foo_bar', 'foo_bar');
$this->assertEquals($bar, $container->getBarService(), '->set() overrides an already defined service');
$this->assertEquals($bar, $container->get('bar'), '->set() overrides an already defined service');
}
@ -90,6 +89,6 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
$container = new \ProjectServiceContainer();
$container->set('bar', $bar = new \stdClass());
$this->assertSame($bar, $container->getFooService()->bar, '->set() overrides an already defined service');
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
}
}

View File

@ -15,8 +15,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
*/
class Container extends AbstractContainer implements TaggedContainerInterface
{
protected $shared = array();
/**
* Constructor.
*/

View File

@ -15,8 +15,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
*/
class ProjectServiceContainer extends Container implements TaggedContainerInterface
{
protected $shared = array();
/**
* Constructor.
*/

View File

@ -15,8 +15,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
*/
class ProjectServiceContainer extends Container implements TaggedContainerInterface
{
protected $shared = array();
/**
* Constructor.
*/

View File

@ -15,8 +15,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
*/
class ProjectServiceContainer extends Container implements TaggedContainerInterface
{
protected $shared = array();
/**
* Constructor.
*/
@ -50,10 +48,7 @@ class ProjectServiceContainer extends Container implements TaggedContainerInterf
*/
protected function getBarService()
{
if (isset($this->shared['bar'])) return $this->shared['bar'];
$instance = new FooClass('foo', $this->get('foo.baz'), $this->getParameter('foo_bar'));
$this->shared['bar'] = $instance;
$this->services['bar'] = $instance = new \FooClass('foo', $this->get('foo.baz'), $this->getParameter('foo_bar'));
$this->get('foo.baz')->configure($instance);
return $instance;
@ -69,10 +64,7 @@ class ProjectServiceContainer extends Container implements TaggedContainerInterf
*/
protected function getFoo_BazService()
{
if (isset($this->shared['foo.baz'])) return $this->shared['foo.baz'];
$instance = call_user_func(array($this->getParameter('baz_class'), 'getInstance'));
$this->shared['foo.baz'] = $instance;
$this->services['foo.baz'] = $instance = call_user_func(array($this->getParameter('baz_class'), 'getInstance'));
call_user_func(array($this->getParameter('baz_class'), 'configureStatic1'), $instance);
return $instance;
@ -88,11 +80,8 @@ class ProjectServiceContainer extends Container implements TaggedContainerInterf
*/
protected function getFooBarService()
{
if (isset($this->shared['foo_bar'])) return $this->shared['foo_bar'];
$class = $this->getParameter('foo_class');
$instance = new $class();
$this->shared['foo_bar'] = $instance;
$this->services['foo_bar'] = $instance = new $class();
return $instance;
}
@ -109,10 +98,7 @@ class ProjectServiceContainer extends Container implements TaggedContainerInterf
{
require_once '%path%foo.php';
if (isset($this->shared['method_call1'])) return $this->shared['method_call1'];
$instance = new FooClass();
$this->shared['method_call1'] = $instance;
$this->services['method_call1'] = $instance = new \FooClass();
$instance->setBar($this->get('foo'));
$instance->setBar($this->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE));
if ($this->has('foo')) {
@ -135,10 +121,7 @@ class ProjectServiceContainer extends Container implements TaggedContainerInterf
*/
protected function getFactoryServiceService()
{
if (isset($this->shared['factory_service'])) return $this->shared['factory_service'];
$instance = $this->get('foo.baz')->getInstance();
$this->shared['factory_service'] = $instance;
$this->services['factory_service'] = $instance = $this->get('foo.baz')->getInstance();
return $instance;
}