This document provides an overview of dependency injection (DI) and aspect-oriented programming (AOP). It discusses some of the basic problems that DI and AOP aim to address, such as tight coupling between classes and cross-cutting concerns. It provides examples of implementing DI using a service container in Symfony and Google Guice-style annotations. It also demonstrates how AOP can be used for logging and caching through interceptors and pointcuts. Overall, the document introduces key concepts and patterns in DI and AOP through code examples.
TeamStation AI System Report LATAM IT Salaries 2024
DI and AOP explained
1. What is this DI and AOP stuff anyway...
Friday, June 7, 13
2. About Me
Currently BBC Sport (Freelancer)
Lived in Japan for 15 years - love sushi
Love frameworks - not just PHP ones
Involved in Lithium and BEAR.Sunday projects
Richard McIntyre - @mackstar
Friday, June 7, 13
4. Most Basic Example - Problem
class Mailer
{
private $transport;
public function __construct()
{
$this->transport = 'sendmail';
}
// ...
}
Friday, June 7, 13
6. Easily becomes an inheritance mess
Sport_Lib_Builder_GenericStatsAbstract
Sport_Lib_Builder_GenericStats_Cricket_Table
Sport_Lib_Builder_GenericStats_Cricket_NarrowTable
Sport_Lib_Builder_GenericStats_CricketAbstract
Sport_Lib_API_GenericStats_Cricket
Sport_Lib_API_GenericStatsAbstract
Sport_Lib_Service_SportsData_Cricket
Sport_Lib_Service_SportsData
Sport_Lib_ServiceAbstract
Friday, June 7, 13
7. DI for a 5 year old
When you go and get things out of the refrigerator for yourself, you can
cause problems. You might leave the door open, you might get something
Mommy or Daddy doesn't want you to have. You might even be looking
for something we don't even have or which has expired.
What you should be doing is stating a need, "I need something to drink
with lunch," and then we will make sure you have something when you
sit down to eat.
Friday, June 7, 13
8. Something like this...
Application needs Foo, which needs Bar, which needs Bim, so:
Application creates Bim
Application creates Bar and gives it Bim
Application creates Foo and gives it Bar
Application calls Foo
Foo calls Bar
Bar does something
Friday, June 7, 13
11. class Mailer
{
private $transport;
public function __construct($transport)
{
$this->transport = $transport;
}
// ...
}
use SymfonyComponentDependencyInjectionContainerBuilder;
$container = new ContainerBuilder();
$container->register('mailer', 'Mailer');
Symfony2 Example
Friday, June 7, 13
12. class Mailer
{
private $transport;
public function __construct($transport)
{
$this->transport = $transport;
}
// ...
}
use SymfonyComponentDependencyInjectionContainerBuilder;
$container = new ContainerBuilder();
$container->register('mailer', 'Mailer');
use SymfonyComponentDependencyInjectionContainerBuilder;
$container = new ContainerBuilder();
$container
->register('mailer', 'Mailer')
->addArgument('sendmail');
Symfony2 Example
Friday, June 7, 13
20. Tips
Test first in isolation
Don’t need to wire together to test (Eg Environment etc)
integration tests are expensive.
When you do wire together with test/mock classes as needed
Duck Type your code / Use interfaces
Friday, June 7, 13
26. Laravel 4 example
class MyConcreteClass implements MyInterface
{
class MyClass
{
public function __construct(MyInterface $my_injection)
{
$this->my_injection = $my_injection;
}
}
App::bind('MyInterface', 'MyConcreteClass');
Friday, June 7, 13
28. Google Guice
Guice alleviates the need for factories and the use of ‘new’ in
your ‘Java’a code
Think of Guice's @Inject as the new new. You will still need
to write factories in some cases, but your code will not
depend directly on them. Your code will be easier to change,
unit test and reuse in other contexts.
Ray.DI
Friday, June 7, 13
30. class Mailer implements MailerInterface
{
private $transport;
/**
* @Inject
* @Named("transport_type")
*/
public function __construct($transport)
{
$this->transport = $transport;
}
}
interface MailerInterface {}
PHP Google Guice Clone
Ray.DI
Friday, June 7, 13
31. class Mailer implements MailerInterface
{
private $transport;
/**
* @Inject
* @Named("transport_type")
*/
public function __construct($transport)
{
$this->transport = $transport;
}
}
interface MailerInterface {}
class NewsletterManager
{
public $mailer;
/**
* @Inject
*/
public function __construct(MailerInterface $mailer)
{
$this->mailer = $mailer;
}
}
PHP Google Guice Clone
Ray.DI
Friday, June 7, 13
32. class NewsletterModule extends AbstractModule
{
protected function configure()
{
$this->bind()->annotatedWith('transport_type')->toInstance('sendmail');
$this->bind('MailerInterface')->to('Mailer');
}
}
Friday, June 7, 13
33. class NewsletterModule extends AbstractModule
{
protected function configure()
{
$this->bind()->annotatedWith('transport_type')->toInstance('sendmail');
$this->bind('MailerInterface')->to('Mailer');
}
} $di = Injector::create([new NewsletterModule]);
$newsletterManager = $di->getInstance('NewsletterManager');
Friday, June 7, 13
34. class NewsletterModule extends AbstractModule
{
protected function configure()
{
$this->bind()->annotatedWith('transport_type')->toInstance('sendmail');
$this->bind('MailerInterface')->to('Mailer');
}
} $di = Injector::create([new NewsletterModule]);
$newsletterManager = $di->getInstance('NewsletterManager');
$works = ($newsletterManager->mailer instanceof MailerInterface);
Friday, June 7, 13
35. Problems?/Gochas
1. Overly abstracted code
2. Easy to go crazy with it
3. Too many factory classes
4. Easy to loose what data is where
5. Container is like super global variable
Friday, June 7, 13
38. The Problem
function addPost() {
$log->writeToLog("Entering addPost");
// Business Logic
$log->writeToLog("Leaving addPost");
}
Friday, June 7, 13
39. The Problem
function addPost() {
$log->writeToLog("Entering addPost");
// Business Logic
$log->writeToLog("Leaving addPost");
}
function addPost() {
$authentication->validateAuthentication($user);
$authorization->validateAccess($user);
// Business Logic
}
Friday, June 7, 13
40. Core Class Aspect Class
AOP Framework
Proxy Class
Continue Process
Friday, June 7, 13
41. Lithium Example -Logging in your model
namespace appmodels;
use lithiumutilcollectionFilters;
use lithiumutilLogger;
Filters::apply('appmodelsPost', 'save', function($self, $params, $chain) {
Logger::write('info', $params['data']['title']);
return $chain->next($self, $params, $chain);
});
Friday, June 7, 13