SlideShare a Scribd company logo
1 of 28
Download to read offline
Migrating to
Dependency Injection
@josh_adell
www.servicetrade.com
blog.everymansoftware.com
github.com/jadell/neo4jphp
https://joind.in/10419
Legacy Code

Began with PHP 5.0 (now 5.3)
~80k LoC
Mixed PHP & HTML
3 x functions.php with ~9k LoC each
magic_quotes AND register_globals
No abstract classes or interfaces
Tightly coupled components
No tests
class UserRepository {
public function findUser($id) {
$db = new Database(/* connection params*/);
$userInfo = $db->query(/* User query with $id */);
$user = new User();
$user->setProperties($userInfo);
return $user;
}
}
========================================================
class UserController {
public function getUser() {
$repo = new UserRepository();
return $repo->findUser($_GET['id']);
}
}
Dependency Injection (DI)
Components should not
create the other components
on which they depend.
Injector injects Dependencies into Consumers
class PageController {
public function __construct(
Database $db) {
$this->repo = new Repository($db);
}
}
========================================================
class PageController {
public function __construct(
Repository $repo) {
$this->repo = $repo;
}
}
DI Container

Wires objects together
I like Pimple: http://pimple.sensiolabs.org/
Parameters
Services / Shared Objects
Factory Services
Factory Callbacks
$di = new Pimple();
// Parameters
$di['dbHost'] = "localhost";
$di['dbUser'] = "username";
$di['dbPass'] = "password";
// Services / Shared Objects
$di['database'] = function ($di) {
return new Database($di['dbHost'], $di['dbUser'], $di
['dbPass']);
};
$di['userRepository'] = function ($di) {
return new UserRepository($di['database]);
};
// Factory Services
$di['user'] = $di->factory(function () {
return new User();
});
// Factory Callbacks
$di['userFactory'] = $di->protect(function ($name) {
return new User($name);
});
Re-architect the application
so that object instantiation
only occurs in the DI Container.
Re-architect the application
so the DI Container
is only referenced from the DI Container.
Why Bother?

Testing / Quality
Maintenance
Extensibility
Flexibility
One Step at a Time
1.
2.
3.

Create a DI factory method for the class
Replace "new" with calls to the DI factory method
a.
b.

Move all shared objects to the constructor
Move all factory creations to anonymous function in the constructor

a.
b.

Pass in shared objects from the DI Container
Pass in factories callbacks from the DI Container

4.

Repeat from Step 1 for all classes
class UserRepository {
public function findUser($id) {
$db = new Database(/* connection params*/);
$userInfo = $db->query(/* User query with $id */);
$user = new User();
$user->setProperties($userInfo);
return $user;
}
}
========================================================
class UserController {
public function getUser() {
$repo = new UserRepository();
return $repo->findUser($_GET['id']);
}
}
Step #1: DI Container method
$di['userRepository'] = function () {
return new UserRepository();
};
Step #2: Replace “new”
class UserController {
public function getUser() {
global $di;
$repo = $di['userRepository'];
return $repo->findUser($_GET['id']);
}
}
Step #3a: Move shared objects
class UserRepository {
public function __construct() {
$this->db = new Database(/* connection params*/);
}
public function findUser($id) {
$userInfo = $this->db->query(/* User query with $id */);
$user = new User();
$user->setProperties($userInfo);
return $user;
}
}
Step #3b: Move factory creation
class UserRepository {
public function __construct() {
$this->db = new Database(/* connection params*/);
$this->userFactory = function () {
return new User();
};
}
public function findUser($id) {
$userInfo = $this->db->query(/* User query with $id */);
$user = call_user_func($this->userFactory);
$user->setProperties($userInfo);
return $user;
}
}
Step #4a: Pass in shared objects
$di['database'] = function () {
return new Database();
};
$di['userRepository'] = function (
$di) {
return new UserRepository(
$di['database']);
};
========================================================
class UserRepository {
public function __construct(
Database $db) {
$this->db = $db;
$this->userFactory = function () {
return new User();
};
}
// ...
Step #4b: Pass in factory callbacks
$di['userFactory'] = $di->protect(function () {
return new User();
});
$di['userRepository'] = function ($di) {
return new UserRepository($di['database'], $di['userFactory']);
};
========================================================
class UserRepository {
public function __construct(Database $db, callable $userFactory) {
$this->db = $db;
$this->userFactory = $userFactory;
}
// ...
Done with UserRepository!
class UserRepository {
public function __construct(Database $db, callable $userFactory) {
$this->db = $db;
$this->userFactory = $userFactory;
}
public function findUser($id) {
$userInfo = $this->db->query(/* User query with $id */);
$user = call_user_func($this->userFactory);
$user->setProperties($userInfo);
return $user;
}
}
Repeat for UserController
$di['userController'] = function ($di) {
return new UserController($di['userRepository']);
};
========================================================

class UserController {
public function __construct(UserRepository $repo) {
$this->userRepo = $repo;
}
public function getUser() {
global $di;
$repo = $di['userRepository'];
return $this->userRepo->findUser($_GET['id']);
}
}
That seems like a lot of steps
New Requirement

Every time a user submits a report,
send an email.
Setup Event Publisher
class User {
public function __construct(
EventEmitter $ee) {
$this->event = $ee;
}
public function submitReport(Report $report) {
// ...
$this->event->publish('newReport', $this, $report);
}
}
Setup Event Subscribers
$di['eventEmitter'] = function () {
return new EventEmitter();
};
$di['emailService'] = function ($di) {
return new EmailService();
};
$di['userFactory'] = $di->protect(function () use ($di)) {
$di['eventEmitter']->subscribe('newReport', $di['emailService']);
return new User($di['eventEmitter']);
});
I have to admit, it's getting better
Questions?
class Presentation {
public function __construct(Presenter $presenter) {
$this->presenter = $presenter;
}
public function askQuestion(Question $question) {
return $this->presenter->answer($question);
}
}
@josh_adell
www.servicetrade.com
blog.everymansoftware.com
github.com/jadell/neo4jphp
http://pimple.sensiolabs.org/
http://martinfowler.com/articles/injection.html

https://joind.in/10419

More Related Content

What's hot

Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介Jace Ju
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Vladyslav Riabchenko
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreNicolas Carlo
 
Impact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesImpact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesOdoo
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov
 
Persistent Memoization with HTML5 indexedDB and jQuery Promises
Persistent Memoization with HTML5 indexedDB and jQuery PromisesPersistent Memoization with HTML5 indexedDB and jQuery Promises
Persistent Memoization with HTML5 indexedDB and jQuery PromisesRay Bellis
 
Object-oriented Javascript
Object-oriented JavascriptObject-oriented Javascript
Object-oriented JavascriptDaniel Ku
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashBret Little
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 

What's hot (20)

Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
SOLID PRINCIPLES
SOLID PRINCIPLESSOLID PRINCIPLES
SOLID PRINCIPLES
 
Drupal7 dbtng
Drupal7  dbtngDrupal7  dbtng
Drupal7 dbtng
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 
Wakanday JS201 Best Practices
Wakanday JS201 Best PracticesWakanday JS201 Best Practices
Wakanday JS201 Best Practices
 
Design Patterns
Design PatternsDesign Patterns
Design Patterns
 
Impact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesImpact of the New ORM on Your Modules
Impact of the New ORM on Your Modules
 
Sqlite perl
Sqlite perlSqlite perl
Sqlite perl
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 
Persistent Memoization with HTML5 indexedDB and jQuery Promises
Persistent Memoization with HTML5 indexedDB and jQuery PromisesPersistent Memoization with HTML5 indexedDB and jQuery Promises
Persistent Memoization with HTML5 indexedDB and jQuery Promises
 
Polyglot parallelism
Polyglot parallelismPolyglot parallelism
Polyglot parallelism
 
Object-oriented Javascript
Object-oriented JavascriptObject-oriented Javascript
Object-oriented Javascript
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and Lodash
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Lodash js
Lodash jsLodash js
Lodash js
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 

Similar to Migrating to dependency injection

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionPhilip Norton
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8Alexei Gorobets
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...go_oh
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection apiMatthieu Aubry
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and PimpleDQNEO
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Yevhen Kotelnytskyi
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overviewjsmith92
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Jeff Carouth
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design PatternsBobby Bouwmann
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXDrupalSib
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Fabien Potencier
 

Similar to Migrating to dependency injection (20)

ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Drupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency InjectionDrupal 8 Services And Dependency Injection
Drupal 8 Services And Dependency Injection
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Dependency injection in Drupal 8
Dependency injection in Drupal 8Dependency injection in Drupal 8
Dependency injection in Drupal 8
 
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection api
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and Pimple
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
PHP 5.3 Overview
PHP 5.3 OverviewPHP 5.3 Overview
PHP 5.3 Overview
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Laravel Design Patterns
Laravel Design PatternsLaravel Design Patterns
Laravel Design Patterns
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
 

Recently uploaded

WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdfSandro Moreira
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...apidays
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamUiPathCommunity
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Bhuvaneswari Subramani
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 

Recently uploaded (20)

WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​Elevate Developer Efficiency & build GenAI Application with Amazon Q​
Elevate Developer Efficiency & build GenAI Application with Amazon Q​
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 

Migrating to dependency injection

  • 3. Legacy Code Began with PHP 5.0 (now 5.3) ~80k LoC Mixed PHP & HTML 3 x functions.php with ~9k LoC each magic_quotes AND register_globals No abstract classes or interfaces Tightly coupled components No tests
  • 4. class UserRepository { public function findUser($id) { $db = new Database(/* connection params*/); $userInfo = $db->query(/* User query with $id */); $user = new User(); $user->setProperties($userInfo); return $user; } } ======================================================== class UserController { public function getUser() { $repo = new UserRepository(); return $repo->findUser($_GET['id']); } }
  • 5. Dependency Injection (DI) Components should not create the other components on which they depend. Injector injects Dependencies into Consumers
  • 6. class PageController { public function __construct( Database $db) { $this->repo = new Repository($db); } } ======================================================== class PageController { public function __construct( Repository $repo) { $this->repo = $repo; } }
  • 7. DI Container Wires objects together I like Pimple: http://pimple.sensiolabs.org/ Parameters Services / Shared Objects Factory Services Factory Callbacks
  • 8. $di = new Pimple(); // Parameters $di['dbHost'] = "localhost"; $di['dbUser'] = "username"; $di['dbPass'] = "password"; // Services / Shared Objects $di['database'] = function ($di) { return new Database($di['dbHost'], $di['dbUser'], $di ['dbPass']); }; $di['userRepository'] = function ($di) { return new UserRepository($di['database]); };
  • 9. // Factory Services $di['user'] = $di->factory(function () { return new User(); }); // Factory Callbacks $di['userFactory'] = $di->protect(function ($name) { return new User($name); });
  • 10. Re-architect the application so that object instantiation only occurs in the DI Container. Re-architect the application so the DI Container is only referenced from the DI Container.
  • 11. Why Bother? Testing / Quality Maintenance Extensibility Flexibility
  • 12. One Step at a Time 1. 2. 3. Create a DI factory method for the class Replace "new" with calls to the DI factory method a. b. Move all shared objects to the constructor Move all factory creations to anonymous function in the constructor a. b. Pass in shared objects from the DI Container Pass in factories callbacks from the DI Container 4. Repeat from Step 1 for all classes
  • 13. class UserRepository { public function findUser($id) { $db = new Database(/* connection params*/); $userInfo = $db->query(/* User query with $id */); $user = new User(); $user->setProperties($userInfo); return $user; } } ======================================================== class UserController { public function getUser() { $repo = new UserRepository(); return $repo->findUser($_GET['id']); } }
  • 14. Step #1: DI Container method $di['userRepository'] = function () { return new UserRepository(); };
  • 15. Step #2: Replace “new” class UserController { public function getUser() { global $di; $repo = $di['userRepository']; return $repo->findUser($_GET['id']); } }
  • 16. Step #3a: Move shared objects class UserRepository { public function __construct() { $this->db = new Database(/* connection params*/); } public function findUser($id) { $userInfo = $this->db->query(/* User query with $id */); $user = new User(); $user->setProperties($userInfo); return $user; } }
  • 17. Step #3b: Move factory creation class UserRepository { public function __construct() { $this->db = new Database(/* connection params*/); $this->userFactory = function () { return new User(); }; } public function findUser($id) { $userInfo = $this->db->query(/* User query with $id */); $user = call_user_func($this->userFactory); $user->setProperties($userInfo); return $user; } }
  • 18. Step #4a: Pass in shared objects $di['database'] = function () { return new Database(); }; $di['userRepository'] = function ( $di) { return new UserRepository( $di['database']); }; ======================================================== class UserRepository { public function __construct( Database $db) { $this->db = $db; $this->userFactory = function () { return new User(); }; } // ...
  • 19. Step #4b: Pass in factory callbacks $di['userFactory'] = $di->protect(function () { return new User(); }); $di['userRepository'] = function ($di) { return new UserRepository($di['database'], $di['userFactory']); }; ======================================================== class UserRepository { public function __construct(Database $db, callable $userFactory) { $this->db = $db; $this->userFactory = $userFactory; } // ...
  • 20. Done with UserRepository! class UserRepository { public function __construct(Database $db, callable $userFactory) { $this->db = $db; $this->userFactory = $userFactory; } public function findUser($id) { $userInfo = $this->db->query(/* User query with $id */); $user = call_user_func($this->userFactory); $user->setProperties($userInfo); return $user; } }
  • 21. Repeat for UserController $di['userController'] = function ($di) { return new UserController($di['userRepository']); }; ======================================================== class UserController { public function __construct(UserRepository $repo) { $this->userRepo = $repo; } public function getUser() { global $di; $repo = $di['userRepository']; return $this->userRepo->findUser($_GET['id']); } }
  • 22. That seems like a lot of steps
  • 23. New Requirement Every time a user submits a report, send an email.
  • 24. Setup Event Publisher class User { public function __construct( EventEmitter $ee) { $this->event = $ee; } public function submitReport(Report $report) { // ... $this->event->publish('newReport', $this, $report); } }
  • 25. Setup Event Subscribers $di['eventEmitter'] = function () { return new EventEmitter(); }; $di['emailService'] = function ($di) { return new EmailService(); }; $di['userFactory'] = $di->protect(function () use ($di)) { $di['eventEmitter']->subscribe('newReport', $di['emailService']); return new User($di['eventEmitter']); });
  • 26. I have to admit, it's getting better
  • 27. Questions? class Presentation { public function __construct(Presenter $presenter) { $this->presenter = $presenter; } public function askQuestion(Question $question) { return $this->presenter->answer($question); } }