oop is more than cars and dogs

63
OOP is More Than Cars and Dogs Chris Tankersley php[tek] 2015 php[tek] 2015 1

Upload: chris-tankersley

Post on 21-Jul-2015

132 views

Category:

Technology


2 download

TRANSCRIPT

OOP is More Than Cars and Dogs

Chris Tankersley

php[tek] 2015

php[tek] 2015 1

Who Am I

• PHP Programmer for over 10 years

• Work/know a lot of different languages, even COBOL

• Primarily do Zend Framework 2

• https://github.com/dragonmantank

php[tek] 2015 2

Quick Vocabulary Lesson

• Class – Definition of code

• Object – Instantiation of a Class

• Member – Variable belonging to a class

• Method – Function belonging to a class

There will be more as we go along

php[tek] 2015 3

php[tek] 2015 4

Class

class Employee {

protected $name; // This is a member

protected $number;

// This is a Method

public function setData($data) {

$this->name = $data['name'];

$this->number = $data['number'];

}

public function viewData() {

echo <<<ENDTEXT

Name: {$this->name}

Number: {$this->number}

ENDTEXT;

}

}

Object

<?php

$manager= new Manager();

// ^

// |

// `--- This is the Object

php[tek] 2015 5

Why are we using OOP?

php[tek] 2015 6

Let’s count the reasons

• Because we’re told to, procedural programming leads to spaghetti code

• We deal with objects every day, so it shouldn’t be too hard

• We want to allow for code re-use

• We want to group like code together

• We want to easily extend our code

• We want to be able to easily test our code

php[tek] 2015 7

Getting OOP Right is Complicated

php[tek] 2015 8

php[tek] 2015 9

php[tek] 2015 10

php[tek] 2015 11

php[tek] 2015 12

php[tek] 2015 13

php[tek] 2015 14

Can a Dog have Wheels?

• Discuss (or listen to me talk some more)

php[tek] 2015 15

Inheritance

php[tek] 2015 16

What we’re all taught

• Classes are “things” in the real world

• We should construct class members based on Attributes• Number of wheels

• Sound it makes

• We should construct class methods based on “Actions”• Running

• Speaking

• Jumping

php[tek] 2015 17

New Vocabulary

• Parent Class – Class that is extended

• Child Class – Class that is extending another class

In PHP, a class can be both a Child and a Parent at the same time

php[tek] 2015 18

Where I Learned It

php[tek] 2015 19

Our Structure

php[tek] 2015 20

Employee

Manager Scientist Laborer

The Employee Class

php[tek] 2015 21

abstract class Employee {

protected $name; // Employee Name

protected $number; // Employee Number

public function setData($data) {

$this->name = $data['name'];

$this->number = $data['number'];

}

public function viewData() {

echo <<<ENDTEXT

Name: {$this->name}

Number: {$this->number}

ENDTEXT;

}

}

The Manager Class

php[tek] 2015 22

class Manager extends Employee {

protected $title; // Employee Title

protected $dues; // Golf Dues

public function setData($data) {

parent::setData($data);

$this->title = $data['title'];

$this->dues = $data['dues'];

}

public function viewData() {

parent::viewData();

echo <<<ENDTEXT

Title: {$this->title}

Golf Dues: {$this->dues}

ENDTEXT;

}

}

The Scientist Class

php[tek] 2015 23

class Scientist extends Employee {

protected $pubs; // Number of Publications

public function setData($data) {

parent::setData($data);

$this->pubs = $data['pubs'];

}

public function viewData() {

parent::viewData();

echo <<<ENDTEXT

Publications: {$this->pubs}

ENDTEXT;

}

}

The Laborer Class

php[tek] 2015 24

class Laborer extends Employee {

}

What does this teach us?

• Inheritance

• Makes it easier to group code together and share it amongst classes

• Allows us to extend code as needed

• PHP allows Single inheritance

php[tek] 2015 25

We use it all the time

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

Class IndexController extends AbstractActionController {

public function indexAction() {

/** @var \Vendor\VendorService $vendor */

$vendor = $this->serviceLocator->get('Vendor\VendorService');

$view = new ViewModel();

return $view;

}

} php[tek] 2015 26

Why it Works (Most of the time, Kinda)

• Allows us to extend things we didn’t necessarily create

• Encourages code re-use

• Allows developers to abstract away things

php[tek] 2015 27

How to use it

• Understand the difference between Public, Protected, and Private• Public – Anyone can use this, even children

• Protected – Anything internal can use this, even children

• Private – This is mine, hands off

• Abstract vs Concrete Classes• Abstract classes cannot be instantiated directly, they must be extended

php[tek] 2015 28

The Employee Class

php[tek] 2015 29

abstract class Employee {

protected $name; // Employee Name

protected $number; // Employee Number

public function setData($data) {

$this->name = $data['name'];

$this->number = $data['number'];

}

public function viewData() {

echo <<<ENDTEXT

Name: {$this->name}

Number: {$this->number}

ENDTEXT;

}

}

The Manager Class

php[tek] 2015 30

class Manager extends Employee {

protected $title; // Employee Title

protected $dues; // Golf Dues

public function setData($data) {

parent::setData($data);

$this->title = $data['title'];

$this->dues = $data['dues'];

}

public function viewData() {

parent::viewData();

echo <<<ENDTEXT

Title: {$this->title}

Golf Dues: {$this->dues}

ENDTEXT;

}

}

An Example

// Fatal error: Cannot instantiate abstract class Employee

$employee = new Employee();

// We can do this though!

$manager = new Manager();

// Fatal error: Cannot access protected property Manager::$name

$manager->name = 'Bob McManager’;

// setData is public, so we can use that

$manager->setData(['name' => 'Bob McManager’,'number' => 1]);

// We can also view the data, since it's public

$manager->viewData();

php[tek] 2015 31

Why can Inheritance Be Bad

• PHP only allows Single Inheritance on an Class• You can have a series of Inheritance though, for example CEO extends

Manager, Manager extends Employee

• Long inheritance chains can be a code smell

• Private members and methods cannot be used by Child classes

• Single Inheritance can make it hard to ‘bolt on’ new functionality between disparate classes

php[tek] 2015 32

Composition over Inheritance

php[tek] 2015 33

The General Idea

• Classes contain other classes to do work and extend that way, instead of through Inheritance

• Interfaces define “contracts” that objects will adhere to

• Your classes implement interfaces to add needed functionality

php[tek] 2015 34

Interfaces

interface EmployeeInterface {

protected $name;

protected $number;

public function getName();

public function setName($name);

public function getNumber();

public function setNumber($number);

}

interface ManagerInterface {

protected $golfHandicap;

public function getHandicap();

public function setHandicap($handicap);

}

php[tek] 2015 35

Interface Implementation

class Employee implements EmployeeInterface {

public function getName() {

return $this->name;

}

public function setName($name) {

$this->name = $name;

}

}

class Manager implements EmployeeInterface, ManagerInterface {

// defines the employee getters/setters as well

public function getHandicap() {

return $this->handicap;

}

public function setHandicap($handicap) {

$this->handicap = $handicap;

}

}

php[tek] 2015 36

This is Good and Bad

• “HAS-A” is tends to be more flexible than “IS-A”

• Somewhat easier to understand, since there isn’t a hierarchy you have to backtrack

• Each class must provide their own Implementation, so can lead to code duplication

php[tek] 2015 37

Traits

• Allows small blocks of code to be defined that can be used by many classes

• Useful when abstract classes/inheritance would be cumbersome• My Posts and Pages classes shouldn’t need to extend a Slugger class just to

generate slugs.

php[tek] 2015 38

Avoid Code-Duplication with Traits

trait EmployeeTrait {

public function getName() {

return $this->name;

}

public function setName($name) {

$this->name = $name;

}

}

class Employee implements EmployeeInterface {

use EmployeeTrait;

}

class Manager implements EmployeeInterface, ManagerInterface {

use EmployeeTrait;

use ManagerTrait;

}

php[tek] 2015 39

Taking Advantage of OOP

php[tek] 2015 40

Coupling

php[tek] 2015 41

What is Coupling?

• Coupling is how dependent your code is on another class

• The more classes you are coupled to, the more changes affect your class

php[tek] 2015 42

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class MapController extends AbstractActionController

{

public function indexAction()

{

// Position is an array with a Latitude and Longitude object

$position = $this->getServiceLocator()->get('Map\Service’)

->getLatLong('123 Main Street', 'Defiance', 'OH');

echo $position->latitude->getPoint();

}

}

php[tek] 2015 43

Law of Demeter

php[tek] 2015 44

Dependency Injection

php[tek] 2015 45

What is Dependency Injection?

• Injecting dependencies into classes, instead of having the class create it

• Allows for much easier testing

• Allows for a much easier time swapping out code

• Reduces the coupling that happens between classes

php[tek] 2015 46

Method Injection

class MapService {

public function getLatLong(GoogleMaps $map, $street, $city, $state) {

return $map->getLatLong($street . ' ' . $city . ' ' . $state);

}

public function getAddress(GoogleMaps $map, $lat, $long) {

return $map->getAddress($lat, $long);

}

}

php[tek] 2015 47

Constructor Injection

class MapService {

protected $map;

public function __construct(GoogleMaps $map) {

$this->map = $map;

}

public function getLatLong($street, $city, $state) {

return $this

->map

->getLatLong($street . ' ' . $city . ' ' . $state);

}

}

php[tek] 2015 48

Setter Injection

class MapService {

protected $map;

public function setMap(GoogleMaps $map) {

$this->map = $map;

}

public function getMap() {

return $this->map;

}

public function getLatLong($street, $city, $state) {

return $this->getMap()->getLatLong($street . ' ' . $city . ' ' . $state);

}

}

php[tek] 2015 49

Single Responsibility Principle

php[tek] 2015 50

Single Responsibility Principle

• Every class should have a single responsibility, and that responsibility should be encapsulated in that class

php[tek] 2015 51

What is a Responsibility?

• Responsibility is a “Reason To Change” – Robert C. Martin

• By having more than one “Reason to Change”, code is harder to maintain and becomes coupled

• Since the class is coupled to multiple responsibilities, it becomes harder for the class to adapt to any one responsibility

php[tek] 2015 52

An Example

/**

* Create a new invoice instance.

*

* @param \Laravel\Cashier\Contracts\Billable $billable

* @param object

* @return void

*/

public function __construct(BillableContract $billable, $invoice)

{

$this->billable = $billable;

$this->files = new Filesystem;

$this->stripeInvoice = $invoice;

}

/**

* Create an invoice download response.

*

* @param array $data

* @param string $storagePath

* @return \Symfony\Component\HttpFoundation\Response

*/

public function download(array $data, $storagePath = null)

{

$filename = $this->getDownloadFilename($data['product']);

$document = $this->writeInvoice($data, $storagePath);

$response = new Response($this->files->get($document), 200, [

'Content-Description' => 'File Transfer',

'Content-Disposition' => 'attachment; filename="'.$filename.'"',

'Content-Transfer-Encoding' => 'binary',

'Content-Type' => 'application/pdf',

]);

$this->files->delete($document);

return $response;

}

php[tek] 2015 53

https://github.com/laravel/cashier/blob/master/src/Laravel/Cashier/Invoice.php

Why is this Bad?

• This single class has the following responsibilities:• Generating totals for the invoice (including discounts/coupons)

• Generating an HTML View of the invoice (Invoice::view())

• Generating a PDF download of the invoice(Invoice::download())• This is coupled to a shell script as well

• Two different displays handled by the class. Adding more means more responsibility

• Coupled to a specific HTML template, the filesystem, the Laravel Views system, and PhantomJS via the shell script

php[tek] 2015 54

How to Improve

• Change responsibility to just building the invoice data

• Move the ‘output’ stuff to other classes

php[tek] 2015 55

Unit Testing

php[tek] 2015 56

[Could not afford licensing fee for Grumpy Testing Picture]

php[tek] 2015 57

This is not a testing talk

• Using Interfaces makes it easier to mock objects

• Reducing coupling and following Demeter’s Law makes you have to mock less objects

• Dependency Injection means you only mock what you need for that test

• Single Responsibility means your test should be short and sweet

• Easier testing leads to more testing

php[tek] 2015 58

Final Thoughts

php[tek] 2015 59

We canmake a dog with wheels!

• Abstract class for Animal

• Class for Dog that extends Animal

• Trait for Wheels

• With the write methodology, we could even unit test this

In the real world, we can now represent a crippled dog

php[tek] 2015 60

Here’s a cute dog instead

php[tek] 2015 61

Thank You!

http://ctankersley.com

[email protected]

@dragonmantank

https://joind.in/13731

php[tek] 2015 62

Photos

• Slide 9 - http://bit.ly/1dkaoxS

• Slide 10 - http://bit.ly/1c4Gc8z

• Slide 11 - http://bit.ly/1R3isBp

• Slide 12 - http://bit.ly/1ScEWRZ

• Slide 13 - http://bit.ly/1Bc0qUv

• Slide 14 - http://bit.ly/1ILhfNV

php[tek] 2015 63