74
Object oriented programming for WordPress plugin development Mike Toppa WordCamp NYC June 9, 2012 @mtoppa www.toppa.com

Object Oriented Programming for WordPress Plugin Development

  • Upload
    mtoppa

  • View
    6.914

  • Download
    0

Embed Size (px)

DESCRIPTION

An introduction to object oriented programming in PHP. This is applicable to WordPress and other CMS/frameworks as well. Note the last half of the slideshow contains the notes for the slides shown in the first half.

Citation preview

Page 1: Object Oriented Programming for WordPress Plugin Development

Object oriented programmingfor WordPress plugin

development

Mike ToppaWordCamp NYC

June 9, 2012

@mtoppawww.toppa.com

Page 2: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

Page 3: Object Oriented Programming for WordPress Plugin Development

@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 4: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

Overview

● Nuts and bolts of classes and objects in PHP● The single responsibility principle● The dependency inversion principle● When to prefer OO to procedural programming

Page 5: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

Page 6: Object Oriented Programming for WordPress Plugin Development

Simple exampleclass Lamp { // property declaration private $maxSafeWatts = 100;

// method declaration public function getMaxSafeWatts() { return $this->maxSafeWatts; }}---------------------------------------------------------------

// instantiate and assign$myLamp = new Lamp();echo $myLamp->getMaxSafeWatts();

Page 7: Object Oriented Programming for WordPress Plugin Development

Rule of thumb:avoid public properties

class Lamp { public $maxSafeWatts = 100;}

---------------------------------------------

$myLamp = new Lamp();

// dangerous to allow this!$myLamp->maxSafeWatts = 'a string to wreck your math';

Page 8: Object Oriented Programming for WordPress Plugin Development

Prefer private propertiesclass Lamp { private $maxSafeWatts = 100;

public setMaxSafeWatts($watts) { if (!is_numeric($watts) || $watts > 125 || $watts < 1) { throw New Exception('invalid value for watts'); }

$this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}

-------------------------------------------------------------------

$myLamp = new Lamp();$myLamp->setMaxSafeWatts(75);

Page 9: Object Oriented Programming for WordPress Plugin Development

Constructors

class Lamp { private $bulb;

public function __construct($bulb) { $this->bulb = $bulb; }}

---------------------------------------------

$myLamp = new Lamp('3 way');

Page 10: Object Oriented Programming for WordPress Plugin Development

Type Hinting

class Lamp { private $bulb;

public function __construct(Bulb $bulb) { $this->bulb = $bulb; }}

---------------------------------------------

$myBulb = new Bulb();$myLamp = new Lamp($bulb);

Page 11: Object Oriented Programming for WordPress Plugin Development

Organizing your classes

@mtoppawww.toppa.com

Page 12: Object Oriented Programming for WordPress Plugin Development

Initializing your OO plugin

// this is the start.php file for a “Lamp” WP plugin...

// require or autoload the “main” class file for your plugin// and then... $lamp = new Lamp();$lamp->run();

// that's it!

Page 13: Object Oriented Programming for WordPress Plugin Development

Abstract classes and inheritance

Lamp

DeskLampFloorLamp HangingLamp

Page 14: Object Oriented Programming for WordPress Plugin Development

Abstract classes and methodsabstract class Lamp { protected $color; protected $maxSafeWatts;

public function setColor($color) { $this->color = $color; return $this->color; }

abstract public function setMaxSafeWatts($watts);}

Page 15: Object Oriented Programming for WordPress Plugin Development

Implementing abstract classesclass FloorLamp extends Lamp { public function setMaxSafeWatts($watts) { /* if numeric and less than 150... */ $this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}------------------------------------------------------------------class DeskLamp extends Lamp { public function setMaxSafeWatts($watts) { /* if numeric and less than 100... */ $this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}

Page 16: Object Oriented Programming for WordPress Plugin Development

Interfaces

Page 17: Object Oriented Programming for WordPress Plugin Development

Using interfaces: the facade pattern

A PHPapplication

Functionsfacade

interface

Drupalfacade

implementation

WordPressfacade

implementation

Some otherfacade

implementation

Page 18: Object Oriented Programming for WordPress Plugin Development

interface FunctionsFacade { public function enqueueStylesheet($handle);}

------------------------------------------------------------------------

class FunctionsFacadeWp implements FunctionsFacade { public function enqueueStylesheet($handle) { return wp_enqueue_style($handle); }}

// we'll look at how to actually use the interface in a few minutes...

Interface Example

Page 19: Object Oriented Programming for WordPress Plugin Development

The SOLID Principles

● Single Responsibility (SRP)

● Open-Closed (OCP)

● Liskov Substitution (LSP)

● Interface Segregation (ISP)

● Dependency Inversion (DIP)

@mtoppawww.toppa.com

Page 20: Object Oriented Programming for WordPress Plugin Development

From LosTechies.com

Page 21: Object Oriented Programming for WordPress Plugin Development

The purpose is to reduce thecomplexity and fragility

of a class

@mtoppawww.toppa.com

Page 22: Object Oriented Programming for WordPress Plugin Development

But what does it mean to do “one thing”?

@mtoppawww.toppa.com

Page 23: Object Oriented Programming for WordPress Plugin Development

Cohesion

@mtoppawww.toppa.com

Page 24: Object Oriented Programming for WordPress Plugin Development

Only one reason to change

@mtoppawww.toppa.com

Page 25: Object Oriented Programming for WordPress Plugin Development

ShashinDisplayer.php

ShashinAlbumDisplayer.php ShashinAlbumDisplayerPicasa.php ShashinAlbumDisplayerTwitpic.php ShashinAlbumDisplayerFlickr.php

ShashinPhotoDisplayer.php ShashinPhotoDisplayerPicasa.php ShashinPhotoDisplayerTwitpic.php ShashinPhotoDisplayerFlickr.php

Classes Example

Page 26: Object Oriented Programming for WordPress Plugin Development

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

// ...}

Methods Example

Page 27: Object Oriented Programming for WordPress Plugin Development

From LosTechies.com

Page 28: Object Oriented Programming for WordPress Plugin Development

Naïve model of a button and lampButton

+ 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 29: Object Oriented Programming for WordPress Plugin Development

Dependency inversion applied

Button

+ poll()

<<interface>>SwitchableDevice

+ turnOn()+ turnOff()

Lamp

This is the Abstract Server pattern

Page 30: Object Oriented Programming for WordPress Plugin Development

interface SwitchableDevice { public function turnOn(); public function turnOff();}

--------------------------------------------------------------

class Lamp implements SwitchableDevice {public function turnOn() {

// code}

public function turnOff() {// code

}}

SwitchableDevice and Lamp

Page 31: Object Oriented Programming for WordPress Plugin Development

class Button { private $switchableDevice;

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

public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); } }}

Button

Page 32: Object Oriented Programming for WordPress Plugin Development

// require or autoload the class files, then...

$lamp = new Lamp();$buttonForLamp = new Button($lamp);$buttonforLamp->poll();

$motor = new Motor();$buttonForMotor = new Button($motor);$buttonForMotor->poll();

Using the Button

Page 33: Object Oriented Programming for WordPress Plugin Development

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

class A should be blissfully unaware of class C

@mtoppawww.toppa.com

Dependency Chains

Page 34: Object Oriented Programming for WordPress Plugin Development

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

@mtoppawww.toppa.com

Page 35: Object Oriented Programming for WordPress Plugin Development

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 36: Object Oriented Programming for WordPress Plugin Development

But don't overdo it:avoid needless complexity

Page 37: Object Oriented Programming for WordPress Plugin Development

When to prefer OOP to procedural programming

@mtoppawww.toppa.com

Page 38: Object Oriented Programming for WordPress Plugin Development

Object oriented programmingfor WordPress plugin

development

Mike ToppaWordCamp NYC

June 9, 2012

@mtoppawww.toppa.com

Skill level

Theory and practice

Won't be an expert

We will be looking at code

Page 39: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

What I'll cover is not specific to WordPress

When you write a plugin you are writing software

Your software should be organized around its use cases, it should not be organized around WordPress' architecture

That is, you should not start with something like a “plugin” class. Your classes should be organized around the business problem they are trying to solved, not around the details of WordPress.

Page 40: Object Oriented Programming for WordPress Plugin Development

@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 41: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

Overview

● Nuts and bolts of classes and objects in PHP● The single responsibility principle● The dependency inversion principle● When to prefer OO to procedural programming

Page 42: Object Oriented Programming for WordPress Plugin Development

@mtoppawww.toppa.com

Page 43: Object Oriented Programming for WordPress Plugin Development

Simple exampleclass Lamp { // property declaration private $maxSafeWatts = 100;

// method declaration public function getMaxSafeWatts() { return $this->maxSafeWatts; }}---------------------------------------------------------------

// instantiate and assign$myLamp = new Lamp();echo $myLamp->getMaxSafeWatts();

A class consists of properties, and methods which perform actions, by manipulating those properties

Encapsulation of related methods and properties. This is what a class really is.

Properties and methods have a visibility (public, private, or protected)

An object is created by instantiating a class (calling new). Then you typically, assign it to a variable, and call its methods as needed

Page 44: Object Oriented Programming for WordPress Plugin Development

Rule of thumb:avoid public properties

class Lamp { public $maxSafeWatts = 100;}

---------------------------------------------

$myLamp = new Lamp();

// dangerous to allow this!$myLamp->maxSafeWatts = 'a string to wreck your math';

Public properties can be used and abused by external code at any time.

Page 45: Object Oriented Programming for WordPress Plugin Development

Prefer private propertiesclass Lamp { private $maxSafeWatts = 100;

public setMaxSafeWatts($watts) { if (!is_numeric($watts) || $watts > 125 || $watts < 1) { throw New Exception('invalid value for watts'); }

$this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}

-------------------------------------------------------------------

$myLamp = new Lamp();$myLamp->setMaxSafeWatts(75);

By requiring them to be set through a method call, you can control what types of values are valid, and what ranges are valid.

Page 46: Object Oriented Programming for WordPress Plugin Development

Constructors

class Lamp { private $bulb;

public function __construct($bulb) { $this->bulb = $bulb; }}

---------------------------------------------

$myLamp = new Lamp('3 way');

The constructor is a special method, used for initializing a class.

It's optional – is called when you call “new”

A constructor does not return anything

It should be used for getting a class into a valid initial state

A common design mistake is to put a lot of complex logic in the constructor, or call it to execute the object's functionality.

Page 47: Object Oriented Programming for WordPress Plugin Development

Type Hinting

class Lamp { private $bulb;

public function __construct(Bulb $bulb) { $this->bulb = $bulb; }}

---------------------------------------------

$myBulb = new Bulb();$myLamp = new Lamp($bulb);

Page 48: Object Oriented Programming for WordPress Plugin Development

Organizing your classes

@mtoppawww.toppa.com

One class per file, and the file name should match the class name

Give the class a meaningful name and its methods meaningful names

Class names and property names should be nouns or noun phrases

Method names should be verbs or verb phrasesGet a real IDE that autocompletes variable names and

method names

Page 49: Object Oriented Programming for WordPress Plugin Development

Initializing your OO plugin

// this is the start.php file for a “Lamp” WP plugin...

// require or autoload the “main” class file for your plugin// and then... $lamp = new Lamp();$lamp->run();

// that's it!

Page 50: Object Oriented Programming for WordPress Plugin Development

Abstract classes and inheritance

Lamp

DeskLampFloorLamp HangingLamp

Page 51: Object Oriented Programming for WordPress Plugin Development

Abstract classes and methodsabstract class Lamp { protected $color; protected $maxSafeWatts;

public function setColor($color) { $this->color = $color; return $this->color; }

abstract public function setMaxSafeWatts($watts);}

An abstract class cannot be implemented directly

It can also have abstract methods, which must be implemented by the child class

Protected methods and properties are essentially private, but can be used by child classes

Page 52: Object Oriented Programming for WordPress Plugin Development

Implementing abstract classesclass FloorLamp extends Lamp { public function setMaxSafeWatts($watts) { /* if numeric and less than 150... */ $this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}------------------------------------------------------------------class DeskLamp extends Lamp { public function setMaxSafeWatts($watts) { /* if numeric and less than 100... */ $this->maxSafeWatts = $watts; return $this->maxSafeWatts; }}

Page 53: Object Oriented Programming for WordPress Plugin Development

Interfaces

An electrical outlet is a great example of an interface. It can power anything designed to plug into it. It doesn't need to know or care about exactly what it's connected to.

Interfaces define a set of methods a class must implement. It's similar to abstract classes in this way, but there is no inheritance.

Page 54: Object Oriented Programming for WordPress Plugin Development

Using interfaces: the facade pattern

A PHPapplication

Functionsfacade

interface

Drupalfacade

implementation

WordPressfacade

implementation

Some otherfacade

implementation

A different implementation of the facade would allow the PHP application to work outside of WordPress, without touching the application's code

When you write a class to implement an interface, it can interact with other classes that know how to talk to that interface, without those other classes having to know anything about your particular implementation of the interface

Page 55: Object Oriented Programming for WordPress Plugin Development

interface FunctionsFacade { public function enqueueStylesheet($handle);}

------------------------------------------------------------------------

class FunctionsFacadeWp implements FunctionsFacade { public function enqueueStylesheet($handle) { return wp_enqueue_style($handle); }}

// we'll look at how to actually use the interface in a few minutes...

Interface Example

Page 56: Object Oriented Programming for WordPress Plugin Development

The SOLID Principles

● Single Responsibility (SRP)

● Open-Closed (OCP)

● Liskov Substitution (LSP)

● Interface Segregation (ISP)

● Dependency Inversion (DIP)

@mtoppawww.toppa.com

Introduced by Bob Martin in his book “Agile Software Development”

Page 57: Object Oriented Programming for WordPress Plugin Development

From LosTechies.com

Applied to classes and methods

Do one thing, do it well, do it only

For methods, this typically means changing the value of only one variable

If you are passing more than 2 or 3 arguments into a method, you are probably doing more than one thing

For classes, it means having a single conceptual responsibility

Page 58: Object Oriented Programming for WordPress Plugin Development

The purpose is to reduce thecomplexity and fragility

of a class

@mtoppawww.toppa.com

We want code that is flexible and easy to understand, not brittle and mind-numbing to read

When a method is manipulating multiple properties and invoking lots of other methods, it can be very hard to test, debug, and change. This is a common reason why developers feel fear when making a change – they don't know what might break

When a class has many methods and multiple responsibilities, it can be hard to understand and difficult to refactor

Page 59: Object Oriented Programming for WordPress Plugin Development

But what does it mean to do “one thing”?

@mtoppawww.toppa.com

Page 60: Object Oriented Programming for WordPress Plugin Development

Cohesion

@mtoppawww.toppa.com

Page 61: Object Oriented Programming for WordPress Plugin Development

Only one reason to change

@mtoppawww.toppa.com

A typical example is when business logic is entangled with the user interface. If you want to develop an RSS feed for a web page, and can't create the feed without tearing apart or copying-and-pasting code that's woven into your HTML, then you've got code that has more than one reason to change.

Page 62: Object Oriented Programming for WordPress Plugin Development

ShashinDisplayer.php

ShashinAlbumDisplayer.php ShashinAlbumDisplayerPicasa.php ShashinAlbumDisplayerTwitpic.php ShashinAlbumDisplayerFlickr.php

ShashinPhotoDisplayer.php ShashinPhotoDisplayerPicasa.php ShashinPhotoDisplayerTwitpic.php ShashinPhotoDisplayerFlickr.php

Classes Example

You can start to see the power of the OO approach here

I can add support for a new photos service by creating a new subclass, instead of having to touch code all over the place, adding a bunch of “if” statements

Page 63: Object Oriented Programming for WordPress Plugin Development

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

// ...}

Methods Example

Page 64: Object Oriented Programming for WordPress Plugin Development

From LosTechies.com

It's common to see code that hard-wires together all the parts, when those connections could be made more flexible and extensible

Page 65: Object Oriented Programming for WordPress Plugin Development

Naïve model of a button and lampButton

+ 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”

This solution violates the DIP

●Button depends directly on Lamp

●Button is not reusable● It can't control, for example, a Motor

Page 66: Object Oriented Programming for WordPress Plugin Development

Dependency inversion applied

Button

+ poll()

<<interface>>SwitchableDevice

+ turnOn()+ turnOff()

Lamp

This is the Abstract Server pattern

What it means

Neither Button nor Lamp “own” the interfaceButtons can now control any device that implements

SwitchableDeviceLamps and other SwitchableDevices can now be

controlled by any object that accepts a SwitchableDevice

Page 67: Object Oriented Programming for WordPress Plugin Development

interface SwitchableDevice { public function turnOn(); public function turnOff();}

--------------------------------------------------------------

class Lamp implements SwitchableDevice {public function turnOn() {

// code}

public function turnOff() {// code

}}

SwitchableDevice and Lamp

Page 68: Object Oriented Programming for WordPress Plugin Development

class Button { private $switchableDevice;

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

public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); } }}

Button

Page 69: Object Oriented Programming for WordPress Plugin Development

// require or autoload the class files, then...

$lamp = new Lamp();$buttonForLamp = new Button($lamp);$buttonforLamp->poll();

$motor = new Motor();$buttonForMotor = new Button($motor);$buttonForMotor->poll();

Using the Button

Page 70: Object Oriented Programming for WordPress Plugin Development

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

class A should be blissfully unaware of class C

@mtoppawww.toppa.com

Dependency Chains

Page 71: Object Oriented Programming for WordPress Plugin Development

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

@mtoppawww.toppa.com

Page 72: Object Oriented Programming for WordPress Plugin Development

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."

Author: Steve Freeman and Nat Pryce

Page 73: Object Oriented Programming for WordPress Plugin Development

But don't overdo it:avoid needless complexity

The complexity of having 44 classes in Shashin is justified by its need for flexibility

You can support a new viewer or a new photo service simply by creating a new subclass. This is much more maintainable and extensible than a single huge file with deeply nested conditionals and unclear dependencies

But if I knew I would never need that kind of flexibility, there would be no justification for creating these layers of abstraction – they would just be needless complexity

Page 74: Object Oriented Programming for WordPress Plugin Development

When to prefer OOP to procedural programming

@mtoppawww.toppa.com

This can be subjective. For me, it hurts my brain to program procedurally, even for small projects.

For a very small project, OO will usually involve more code

If you can classify the components of an application into objects with properties and methods, and you have an idea of what kind of changes will come in the future, an OO approach is very powerful.

Also, if you want to do unit testing, you need OO code