The document provides an overview of the Symfony Components library and Dependency Injection container. It introduces Dependency Injection as a design pattern where objects receive their dependencies (like collaborators) through constructors or properties rather than creating them directly. It then provides a simple example of using a Dependency Injection container to configure and instantiate objects, avoiding hard dependencies. The container handles resolving dependencies and acts as a service locator.
2. Fabien Potencier
• Serial entrepreneur and developer by passion
• Founder of Sensio (in 1998)
– A services and consulting company
specialized in Web technologies
and Internet marketing (France and USA)
– 70 people
– Open-Source specialists
– Big corporate customers
– Consulting, training, development, web design, … and more
– Sponsor of a lot of Open-Source projects
like symfony and Doctrine
3. Fabien Potencier
• Creator and lead developer of symfony…
• and creator and lead developer of some more OSS:
– symfony components
– Swift Mailer : Powerful component based mailing library for PHP
– Twig : Fexible, fast, and secure template language for PHP
– Pirum : Simple PEAR Channel Server Manager
– Sismo : PHP continuous integration server
– Lime : Easy to use unit testing library for PHP
– Twitto : A web framework in a tweet
– Twittee : A Dependency Injection Container in a tweet
– Pimple : A small PHP 5.3 dependency injection container
4. Fabien Potencier
• Read my technical blog: http://fabien.potencier.org/
• Follow me on Twitter: @fabpot
• Fork my code on Github: http://github.com/fabpot/
6. symfony
• Full-stack framework (MVC architecture)
• symfony provides the infrastructure/tools needed for 95% of the web
projects
• Open-Source (MIT License) since 2005
• Based on
– 11 years of Sensio experience building websites for its customers
– Existing Open-Source projects
8. A bit of history
symfony 1.0 (January 2007) started as a glue between existing
Open-Source libraries
9. A bit of history
symfony 1.1 (June 2008) was a big refactoring of the code base
– Decoupled the main component: like Forms, Routing, Cache, YAML, ORMs, …
sfRequest sfRouting sfLogger sfI18N sfUser sfResponse
sfYAML sfDatabase sfForm sfEventDispatcher sfStorage sfCache sfOutputEscaper
sfValidator sfWidget sfCoreAutoload
platform
10. The symfony (1.2/1.3/1.4) MVC
framework is based on a set of
cohesive but decoupled classes,
the symfony components
11. Symfony Components
• Announced in May 2009
• Standalone components
• Packaged individually
• No dependencies
• Release cycle independent of Symfony, the framework
12. Symfony Components
Dedicated website for each component (with code and documentation)
http://components.symfony-project.org/
Dedicated Subversion and Git repository
http://svn.symfony-project.com/components/
http://github.com/fabpot
13. Symfony Components
They have been migrated to PHP 5.3
http://svn.symfony-project.com/branches/2.0/lib/Symfony/Components
14. Symfony Components
Each “old” PHP 5.2 symfony component has been branched
and a 1.0 version will be released soon
http://svn.symfony-project.com/components/
15. Symfony Components
• Extracted from symfony 1
– Event Dispatcher
– YAML
– Output Escaper
• Written from scratch for Symfony 2
– Dependency Injection Container
– Request Handler
– Templating
• We don’t want to duplicate effort done by Zend Framework
18. Which version?
• This presentation is about the components based on PHP 5.3
• The stable 1.0 branch based on PHP 5.2 has the same feature set and
work exactly in the same way, except:
– The autoloader
– The class names
21. PHP 5.3 technical interoperability standards
« … describes the mandatory requirements
that must be adhered to
for autoloader interoperability »
http://groups.google.com/group/php-standards/web/psr-0-final-proposal
22. What does this mean?
• PHP libraries will finally be 100% technically interoperable and have
optimum autoloading performance
• Symfony 2.0 + Doctrine 2.0 + Zend Framework 2.0
• Load classes from 3 different libraries with one autoloader and one
include path
• Also able to load classes implementing the PEAR naming convention
• Share SplClassLoader implementation:
– http://gist.github.com/221634
• Implement SplClassLoader in C/PHP :)
25. YAML
• YAML is a human friendly data serialization standard for all
programming languages (implementations exist in Perl, Ruby, Python,
Java, …)
• YAML is a great format for your configuration files
• YAML files are as expressive as XML files and as readable as INI files
26. YAML
• Used in symfony for all configuration files
• Used in Doctrine for schema and fixtures
• Used in PHPUnit for TAP output and for DataSet (DbUnit)
27. config:
key: value
foo: [foo, bar]
bar: { foo: bar }
foobar: { foo: [foo, bar] }
28. use SymfonyComponentsYAMLYAML;
// Parse YAML
$config = YAML::load(<<<'EOF'
config:
key: value
foo: [foo, bar]
bar: { foo: bar }
foobar: { foo: [foo, bar] }
EOF
);
// Dump YAML
echo YAML::dump($config);
31. Event Dispatcher
• Symfony Event Dispatcher is a PHP library that provides a lightweight
implementation of the Observer design pattern
• Based on the Cocoa Notification Center
• Used in symfony to provide hooks and allow customizations of default
behaviors sfRequest sfRouting sfLogger sfI18N sfUser sfResponse
– Inject the Web Debug Toolbar sfYAML sfDatabase sfForm sfEventDispatcher sfStorage sfCache sfOutputEscaper
– Inject methods into core Objects sfValidator sfWidget sfCoreAutoload
platform
– I18n management
– …
32. An object (the subject)
maintains a list of its dependents (observers)
and notifies them automatically of any state
changes, usually by calling one of their methods
http://en.wikipedia.org/wiki/Observer_pattern
33. An event dispatcher is a central object
that manages connections
between subjects and observers
34. It is a powerful mechanism to extend applications
without having to change the objects themselves
Associated words: hook, listener, event, subject, …
35. use SymfonyComponentsEventDispatcherEvent;
use SymfonyComponentsEventDispatcherEventDispatcher;
$dispatcher = new EventDispatcher();
// an anonymous listener
$listener = function (Event $event)
{
echo "Hello {$event['name']}n";
};
// register the listener (any PHP callable) with the dispatcher
$dispatcher->connect('foo', $listener);
// notify the event somewhere
$event = new Event(null, 'foo', array('name' => 'Fabien'));
$dispatcher->notify($event);
36. Symfony Event Dispatcher
• The implementation is simple
– No interface to implement
– No need to create an event class for each event
– An event is just a unique identifier
– Some conventions (parameter names)
37. Symfony Event Dispatcher
• Advantages
– Very simple to use
– Easy to add new arguments to the listener
– Very fast
– Very easy to add a new event, just notify it with a unique name
• Disadvantages
– The contract between the listener and the notifier is quite loose
38. Notifications
• Notify : all listeners are called in turn, no feedback to the notifier
– Logging, …
• Notify Until : all listeners are called until one « processes » the event. The
listener that has processed the event can return something to the caller
– Exceptions, Method not found in __call(), …
• Filter : Each listener filters a given value and can change it. The filtered
value is returned to the caller
– HTML content, parameters, …
39. class Response
{
protected $content, $dispatcher;
public function __construct(EventDispatcher $dispatcher, $content)
{
$this->dispatcher = $dispatcher;
$this->content = $content;
}
public function send()
{
$event = new Event($this, 'response.filter_content');
$this->dispatcher->filter($event, $this->content);
echo $event->getReturnValue();
}
}
40. $dispatcher = new EventDispatcher();
// an anonymous listener
$listener = function (Event $event, $content)
{
return '*'.$content.'*';
};
// register the listener
$dispatcher->connect('response.filter_content', $listener);
$response = new Response($dispatcher, 'Hello');
$response->send();
41. Notifiers Dispatcher Listeners
listener connects
1 to ‘response.filter_content’
Response notifies Calls listener
2 ‘response.filter_content’ all listeners is called
42. The Response object knows nothing about the listeners
The listener objects know nothing about the Response one
They communicate through the Dispatcher object
Anybody can listen to the ‘response.filter_content’ event
and acts accordingly
43. Notifiers Dispatcher Listeners
listener connects
1 to response.filter_content
Your class connects
to response.filter_content
Response notifies Calls listener
2 response.filter_content all listeners is called
Your class callback
is called
44. Notifiers Dispatcher
Response notifies Calls
response.filter_content nothing
very small overhead
50. Template Loaders
• No assumption about where and how templates are to be found
– Filesystem
– Database
– Memory, …
• Built-in loaders: FilesystemLoader, ChainLoader, CacheLoader
• Template names are « logical » names:
$loader = new FilesystemLoader('/path/to/templates/%name%.php');
51. Template Renderers
• No assumption about the format of the templates
• Template names are prefixed with the renderer name:
– index == php:index
– user:index
$t = new Engine($loader, array(
'user' => new ProjectTemplateRenderer(),
'php' => new PhpRenderer(),
));
60. « Dependency Injection is where components
are given their dependencies through their
constructors, methods, or directly into fields. »
http://www.picocontainer.org/injection.html
61. class Message
{
public function __construct()
{
$this->output = new Output();
}
}
class Message
{
public function __construct(OutputInterface $output)
{
$this->output = $output;
}
}
62. DI Hello World example
class Message
{
public function __construct(OutputInterface $output, array $options)
{
$this->output = $output;
$this->options = array_merge(array('with_newline' => false), $options);
}
public function say($msg)
{
$this->output->render($msg.($this->options['with_newline'] ? "n" : ''));
}
}
63. DI Hello World example
interface OutputInterface
{
public function render($msg);
}
class Output implements OutputInterface
{
public function render($msg)
{
echo $msg;
}
}
class FancyOutput implements OutputInterface
{
public function render($msg)
{
echo sprintf("033[33m%s033[0m", $msg);
}
}
64. DI Hello World example
$output = new FancyOutput();
$message = new Message($output, array('with_newline' => true));
$message->say('Hello World');
65. A DI container facilitates
objects description and object relationships,
configures and instantiates objects
66. DI Container Hello World example
use SymfonyComponentsDependencyInjectionBuilder;
use SymfonyComponentsDependencyInjectionReference;
$container = new Builder();
$container->register('output', 'FancyOutput');
$container->
register('message', 'Message')->
setArguments(array(new Reference('output'), array('with_newline' => true)))
;
$container->message->say('Hello World!');
67. $message = $container->message;
Get the configuration for the message service
The Message constructor must be given an output service
Get the output object from the container
Create a Message object by passing the constructor arguments
68. $message = $container->message;
is roughly equivalent to
$output = new FancyOutput();
$message = new Message($output, array('with_newline' => true));!
69. $container = new Builder();
$container->register('output', 'FancyOutput');
$container->
register('message', 'Message')->
setArguments(array(new Reference('output'), array('with_newline' => true)))
;
$container->message->say('Hello World!'); PHP
<container xmlns="http://symfony-project.org/2.0/container">
<services> XML
<service id="output" class="FancyOutput" />
<service id="message" class="Message"> XML is validated
<argument type="service" id="output" /> against an XSD
<argument type="collection">
<argument key="with_newline">true</argument>
</argument>
</service>
</services>
</container>
$container = new Builder();
$loader = new XmlFileLoader($container);
$loader->load('services.xml');
74. Loaders & Dumpers
• IniFileLoader
• XmlFileLoader
• YamlFileLoader
• XmlDumper
• YamlDumper
Make your container
• PhpDumper VERY fast
• GraphvizDumper
75. use SymfonyComponentsDependencyInjectionBuilder;
use SymfonyComponentsDependencyInjectionReference;
use SymfonyComponentsDependencyInjectionDumperXmlDumper;
use SymfonyComponentsDependencyInjectionDumperYamlDumper;
use SymfonyComponentsDependencyInjectionDumperPhpDumper;
use SymfonyComponentsDependencyInjectionLoaderXmlFileLoader;
use SymfonyComponentsDependencyInjectionLoaderYamlFileLoader;
$container = new Builder();
$container->register('output', 'FancyOutput');
$container->
register('message', 'Message')->
setArguments(array(new Reference('output'), array('with_newline' => true)))
;
76. $dumper = new XmlDumper($container);
file_put_contents(__DIR__.'/container.xml', $dumper->dump());
$loader = new XmlFileLoader($container);
$loader->load(__DIR__.'/container.xml');
$dumper = new YamlDumper($container);
file_put_contents(__DIR__.'/container.yml', $dumper->dump());
$loader = new YamlFileLoader($container);
$loader->load(__DIR__.'/container.yml');
$dumper = new PhpDumper($container);
echo $dumper->dump();
77. use SymfonyComponentsDependencyInjectionContainer;
use SymfonyComponentsDependencyInjectionReference;
use SymfonyComponentsDependencyInjectionParameter;
class ProjectServiceContainer extends Container
{
protected $shared = array();
protected function getOutputService()
{
if (isset($this->shared['output'])) return $this->shared['output'];
$instance = new FancyOutput();
return $this->shared['output'] = $instance;
}
protected function getMessageService()
{
if (isset($this->shared['message'])) return $this->shared['message'];
$instance = new Message($this->getService('output'), array('with_newline' => true));
return $this->shared['message'] = $instance;
}
}
87. class Article
{
protected $title;
protected $author;
public $full_title; public property
public function __construct($title, Author $author)
{
$this->title = $title;
$this->full_title = $title;
$this->author = $author;
} public method
public function getTitle() { return $this->title; }
public method returning
public function getAuthor() { return $this->author; }
public function __get($key) { return $this->$key; } another object
public function __call($method, $arguments) magic __get()
{
return $this->{'get'.$method}(); magic __call()
}
}
88. class Author
{
protected $name;
public function __construct($name) { $this->name = $name; }
public function getName() { return $this->name; }
}
89. use SymfonyComponentsOutputEscaperEscaper;
$article = new Article(
'foo <br />',
new Author('Fabien <br />')
);
$article = Escaper::escape(ESC_SPECIALCHARS, $article);
echo $article->getTitle()."n";
echo $article->getAuthor()->getName()."n";
echo $article->full_title."n";
echo $article->title."n";
echo $article->title()."n";
90. Escaping Strategy
explicitly ask
for raw data
echo $article->getHtmlContent(ESC_RAW);
echo $article->getTitle(ESC_JS);
change the default
escaping strategy
91. symfony-live.com
with Matthew Weier O’Pheinney
I will reveal the first alpha release of Symfony 2.0!
92. symfony-live.com
with Matthew Weier O’Pheinney
… with Matthew Weier O'Phinney as a special guest
93. Thank you!
My slides on slideshare.com/fabpot
with a bonus: How to use Symfony Components with ZF!
94. Sensio S.A.
92-98, boulevard Victor Hugo
92 115 Clichy Cedex
FRANCE
Tél. : +33 1 40 99 80 80
Contact
Fabien Potencier
fabien.potencier at sensio.com
http://www.sensiolabs.com/
http://www.symfony-project.org/
http://fabien.potencier.org/
95. BO NUS
How to use Symfony Components
within a Zend Framework project?
96. Symfony components in a ZF project
• Symfony Components can make your ZF application better
– More configurable: symfony YAML
– More flexible: symfony Event Dispatcher
– Faster: symfony Dependency Injection
– More secure: symfony Output Escaper
• … and more fun of course
97. Symfony Components in a ZF project
• The examples in this presentation are just to get you started faster
• So, be creative with them. They open all kind of opportunities for your
next Zend Framework project
• And please, give me feedback, and tell me what you do with the
Symfony Components
101. class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function getContainer()
{
if (null === $this->_container)
{
$this->setContainer($this->_initContainer());
}
return $this->_container;
}
protected function _initContainer()
{
require_once '/path/to/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();
Example from Ben Eberlei (he rocks!): http://www.whitewashing.de/blog/articles/118
$container = new sfServiceContainerBuilder();
$loader = new sfServiceContainerLoaderFileXml($container);
$loader->load(dirname(__FILE__).'/configs/resources.xml');
return $container;
}
}
104. class GuestbookController extends Zend_Controller_Action
{
public function indexAction()
{
$guestbook = new Default_Model_Guestbook();
$this->view->entries = $guestbook->fetchAll();
$container = $this->getInvokeArg('bootstrap')->getContainer();
$mailer = $container->mailer;
}
}
105. Dependency Injection Container
• By default in ZF, new resources can be added to the container but cannot
be lazy-loaded
– All resources used by Zend_Application are loaded on every request
• By using symfony Service Container, the resources are lazy-loaded
– Instances and their dependencies are created the first time you get them
• Interesting for resources like DB