57
Dependency Injection for WordPress Plugin Development Mike Toppa WordCamp Nashville April 21, 2012 #wcn12 @mtoppa www.toppa.com

Dependency Injection for Wordpress

  • Upload
    mtoppa

  • View
    5.089

  • Download
    4

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Dependency Injection for Wordpress

Dependency Injection forWordPress Plugin Development

Mike ToppaWordCamp Nashville

April 21, 2012#wcn12

@mtoppawww.toppa.com

Page 2: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Mike Toppa

● Director of Development, WebDevStudios● 17 years of experience in web development,

project management, and team management● Universities: Georgetown, Stanford, Penn● Dot coms: E*Trade, Ask Jeeves● Start-ups: Finexa, Kai's Candy Co● WordPress development for non-profits

Page 3: Dependency Injection for Wordpress

Code is Poetry

@mtoppawww.toppa.com

Page 4: Dependency Injection for Wordpress

@mtoppawww.toppa.com

We want code to be...

● Easy to understand● Easy to change● Reusable (DRY)● Bug free

Page 5: Dependency Injection for Wordpress

“O.P.C” http://abstrusegoose.com/432

So why is it usually like this?

Page 6: Dependency Injection for Wordpress

It happens because we are always in a hurry,and requirements are always changing.

@mtoppawww.toppa.com

Page 7: Dependency Injection for Wordpress

But coding fast and dirtyonly makes us slower in the long run.

@mtoppawww.toppa.com

Page 8: Dependency Injection for Wordpress

“We like to think we spend our time power typing,but we actually spend most of our time

staring into the abyss.”

- Douglas Crockfordprincipal discoverer of JSON,

Creator of JSLint

@mtoppawww.toppa.com

Page 9: Dependency Injection for Wordpress

The ratio of time spent reading code versus writing is well over 10 to 1.

Therefore, making code easy to readmakes it easier to write.

- Bob MartinParaphrased from his book Clean Code

@mtoppawww.toppa.com

Page 10: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Clean code saves time, saves $$

Page 11: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Clean code techniques

● Using meaningful names● Don't repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many more

Page 12: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Clean code techniques

● Using meaningful names● Don't repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many more

Page 13: Dependency Injection for Wordpress

@mtoppawww.toppa.com

The SOLID Principles

● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)

Page 14: Dependency Injection for Wordpress

@mtoppawww.toppa.com

The SOLID Principles

● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)

Page 15: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Shashin

My plugin for displaying albums, photos, and videos from Picasa, Twitpic, and YouTube

(and others coming soon)

Page 16: Dependency Injection for Wordpress

@mtoppawww.toppa.com

I used the new version as a test case for applyingclean code principles to WordPress plugins

Page 17: Dependency Injection for Wordpress
Page 18: Dependency Injection for Wordpress
Page 19: Dependency Injection for Wordpress
Page 20: Dependency Injection for Wordpress
Page 21: Dependency Injection for Wordpress

From LosTechies.com

Page 22: Dependency Injection for Wordpress

@mtoppawww.toppa.com

My Shashin plugin consists of 44 classes, each of which has a meaningful name, follows the SRP,

and “does one thing”

PicasaPhotoDisplayerSettingsMenu

YouTubeSynchronizerUninstall

etc.

Page 23: Dependency Injection for Wordpress

@mtoppawww.toppa.com

class Admin_ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; }

// ...}

Shashin example

Page 24: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Class Autoloading

● The problem:● PHP lacks an equivalent statement to “import” or

“use” for classes● Having to hardcode a bunch of file paths is extra

work, and makes code harder to change

● The solution:● PHP 5.1.2 and spl_autoload_register()● PHP Standards Working Group: PSR-0

Page 25: Dependency Injection for Wordpress

@mtoppawww.toppa.com

PSR-0: Official Description

● Each "_" character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR

● The fully-qualified namespace and class is suffixed with ".php" when loading from the file system

● Alphabetic characters... may be of any combination of lower case and upper case

● ...And other rules about namespaces● Source: https://github.com/php-fig/fig-

standards/blob/master/accepted/PSR-0.md

Page 26: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Admin_ShashinInstall

is translated to

Admin/ShashinInstall.php

PSR-0 Example

Page 27: Dependency Injection for Wordpress

@mtoppawww.toppa.com

// this is at the top of the main file for my Shashin plugin

require_once dirname(__FILE__) . '/../toppa-plugin-libraries-for-wordpress/ToppaAutoLoaderWp.php'; $shashinAutoLoader = new ToppaAutoLoaderWp('/shashin');

// that's it! I can now call “new” on any class under the shashin folder// and its class file will be automatically loaded

Toppa Plugin Libraries Autoloader

Page 28: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Shashin's capabilities are shaped by how its objects are wired together, through

implementation of theDependency Inversion Principle

Page 29: Dependency Injection for Wordpress

From LosTechies.com

Page 30: Dependency Injection for Wordpress

Naïve model of a button and lamp

Button

+ poll()

Lamp

+ turnOn()+ turnOff()

class Button {private $lamp;

public function __construct(Lamp $lamp) {$this->lamp = $lamp;

}

public function poll() {if (/* some condition */) {

$this->lamp->turnOn();}

}}

Example from “Agile Software Development”

Page 31: Dependency Injection for Wordpress

Dependency inversion applied

Button

+ poll()

<<interface>>SwitchableDevice

+ turnOn()+ turnOff()

Lamp

This is the Abstract Server pattern

Page 32: Dependency Injection for Wordpress

class Lamp implements SwitchableDevice {public function turnOn() {

// code}

public function turnOff() {// code

}}

class Button {private $switchableDevice;

public function __construct(SwitchableDevice $switchableDevice) {$this->switchableDevice = $switchableDevice;

}

public function poll() {if (/* some condition */) {

$this->switchableDevice->turnOn();}

}}

Page 33: Dependency Injection for Wordpress

A web of collaborating objects

● The SRP and DIP together drive a “composition” approach to OO design

● From Growing Object Oriented Software, Guided by Tests: "An object oriented system is a web of collaborating objects... The behavior of the system is an emergent property of the composition of the objects - the choice of objects and how they are connected... Thinking of a system in terms of its dynamic communication structure is a significant mental shift from the static classification that most of us learn when being introduced to objects."

Page 34: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Composition(“Has a...”)

vs.

Inheritance(“Is a...”)

Page 35: Dependency Injection for Wordpress

@mtoppawww.toppa.com

The SRP is about objects that do one thing

The DIP is about how to wire them togetherto create working, flexible software

Page 36: Dependency Injection for Wordpress

@mtoppawww.toppa.com

class Button {private $lamp;

public function __construct() {$this->lamp = new Lamp();

}

//...}

Never, ever do this

Page 37: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Instead, you want toinject the object dependency

Dependency injection!

Page 38: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Dependency injection is one of manydesign patterns

for implementing theDependency inversion principle

Page 39: Dependency Injection for Wordpress

@mtoppawww.toppa.com

It comes in two flavors

Page 40: Dependency Injection for Wordpress

@mtoppawww.toppa.com

public function __construct(SwitchableDevice $switchableDevice) {$this->switchableDevice = $switchableDevice;

}

Constructor injection

Page 41: Dependency Injection for Wordpress

@mtoppawww.toppa.com

public function setSwitchableDevice(SwitchableDevice $switchableDevice) {$this->switchableDevice = $switchableDevice;

}

Setter injection

Page 42: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Which to use?

It depends

Page 43: Dependency Injection for Wordpress

@mtoppawww.toppa.com

If class A depends on class B,and class B depends on class C,

class A should be blissfully unaware of class C

Dependency chains

Page 44: Dependency Injection for Wordpress

@mtoppawww.toppa.com

To do this without going insane,you need an injection container

Page 45: Dependency Injection for Wordpress

@mtoppawww.toppa.com

class Lib_ShashinContainer { // … public function getPhotoRefData() { if (!isset($this->photoRefData)) { $this->photoRefData = new Lib_ShashinPhotoRefData(); }

return $this->photoRefData; }

public function getClonablePhoto() { if (!isset($this->clonablePhoto)) { $this->getPhotoRefData(); $this->clonablePhoto = new Lib_ShashinPhoto($this->photoRefData); }

return $this->clonablePhoto; }

Example from Shashin

Page 46: Dependency Injection for Wordpress

@mtoppawww.toppa.com

public function getClonablePhotoCollection() { if (!isset($this->photoCollection)) { $this->getClonablePhoto(); $this->getSettings(); $this->clonablePhotoCollection = new Lib_ShashinPhotoCollection(); $this->clonablePhotoCollection->setClonableDataObject($this->clonablePhoto); $this->clonablePhotoCollection->setSettings($this->settings); }

return $this->clonablePhotoCollection; }

Example continued

Page 47: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Beyond the textbook examples

Page 48: Dependency Injection for Wordpress

@mtoppawww.toppa.com

What to do when you needa new object inside a loop

One solution is cloning

Page 49: Dependency Injection for Wordpress

@mtoppawww.toppa.com

class Admin_ShashinSynchronizerPicasa extends Admin_ShashinSynchronizer { // …

public function syncAlbumPhotos(array $decodedAlbumData) { // …

foreach ($decodedAlbumData['feed']['entry'] as $entry) { $photoData = $this->extractFieldsFromDecodedData($entry, $photoRefData, 'picasa'); // ... $photo = clone $this->clonablePhoto; $photo->set($photoData); $photo->flush(); }

Shashin Example

Page 50: Dependency Injection for Wordpress

@mtoppawww.toppa.com

What if you need a new object inside a loop,but can't know the subtype you'll need

ahead of time?

Let the injection container figure it out

Page 51: Dependency Injection for Wordpress

@mtoppawww.toppa.com

class Public_ShashinLayoutManager { // ... public function setTableBody() { // …

for ($i = 0; $i < count($this->collection); $i++) { // ...

$dataObjectDisplayer = $this->container->getDataObjectDisplayer( $this->shortcode, $this->collection[$i] );

$this->tableBody .= $dataObjectDisplayer->run();

// ... }

Shashin Example

Page 52: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Dependency injection: key benefits

● Makes your object dependencies adaptable to emerging needs

● With an injection container, simplifies managing dependency chains

● Supports “preferring polymorphism to conditionals”, making it easy to add new class subtypes

Page 53: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Will this proliferation of objectseat up all my memory?

No

Page 54: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Use dependency injection to instantiateonly the objects you need,

when you need them

Page 55: Dependency Injection for Wordpress

@mtoppawww.toppa.com

Make immutable objects intoproperties of the container,

so you only need to instantiate them once

Page 56: Dependency Injection for Wordpress

@mtoppawww.toppa.com

“In PHP 5, the infrastructure of the object model was rewritten to work with object handles. Unless you explicitly clone an object by using the clone keyword you will never create behind the scene duplicates of your objects. In PHP 5, there is neither a need to pass objects by reference nor assigning them by reference.”

From http://devzone.zend.com/article/1714

PHP 5 has improved memory management

Page 57: Dependency Injection for Wordpress

But don't overdo it:avoid needless complexity