OOP is More Than Cats
and Dogs
Chris	
  Tankersley	
  
LonestarPHP	
  2015	
  
LonestarPHP	
  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	
  
•  hFps://github.com/dragonmantank	
  
LonestarPHP	
  2015	
   2	
  
Quick Vocabulary Lesson
•  Class	
  –	
  DefiniOon	
  of	
  code	
  
•  Object	
  –	
  InstanOaOon	
  of	
  a	
  Class	
  
•  Member	
  –	
  Variable	
  belonging	
  to	
  a	
  class	
  
•  Method	
  –	
  FuncOon	
  belonging	
  to	
  a	
  class	
  
There	
  will	
  be	
  more	
  as	
  we	
  go	
  along	
  
LonestarPHP	
  2015	
   3	
  
LonestarPHP	
  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	
  
LonestarPHP	
  2015	
   5	
  
Why are we using OOP?
LonestarPHP	
  2015	
   6	
  
Let’s count the reasons
•  Because	
  we’re	
  told	
  to,	
  procedural	
  programming	
  leads	
  to	
  spagheX	
  
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	
  
LonestarPHP	
  2015	
   7	
  
Getting OOP Right can be Complicated
•  Animals	
  can	
  speak,	
  and	
  have	
  legs	
  and	
  fur.	
  Let’s	
  make	
  objects	
  based	
  
on	
  that	
  
•  Dogs	
  are	
  animals,	
  and	
  so	
  are	
  cats	
  
•  What	
  about	
  Fish?	
  
•  Cars	
  have	
  doors,	
  engines,	
  and	
  colors.	
  They	
  only	
  go	
  so	
  fast.	
  Let’s	
  
model	
  that	
  
•  Motorcycles	
  aren’t	
  Cars,	
  so	
  let’s	
  refactor	
  Cars	
  
•  Holy	
  crap	
  there	
  are	
  a	
  lot	
  of	
  engines…	
  and	
  wheels…	
  	
  
LonestarPHP	
  2015	
   8	
  
Can a Dog have Wheels?
•  Discuss	
  (or	
  listen	
  to	
  me	
  talk	
  some	
  more)	
  
LonestarPHP	
  2015	
   9	
  
Inheritance
LonestarPHP	
  2015	
   10	
  
What we’re all taught
•  Classes	
  are	
  “things”	
  in	
  the	
  real	
  world	
  
•  We	
  should	
  construct	
  class	
  members	
  based	
  on	
  AFributes	
  
•  Number	
  of	
  wheels	
  
•  Sound	
  it	
  makes	
  
•  We	
  should	
  construct	
  class	
  methods	
  based	
  on	
  “AcOons”	
  
•  Running	
  
•  Speaking	
  
•  Jumping	
  
LonestarPHP	
  2015	
   11	
  
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	
  Ome	
  
LonestarPHP	
  2015	
   12	
  
Where I Learned It
LonestarPHP	
  2015	
   13	
  
Our Structure
LonestarPHP	
  2015	
   14	
  
Employee	
  
Manager	
   ScienOst	
   Laborer	
  
The Employee Class
LonestarPHP	
  2015	
   15	
  
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
LonestarPHP	
  2015	
   16	
  
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
LonestarPHP	
  2015	
   17	
  
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
LonestarPHP	
  2015	
   18	
  
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	
  
LonestarPHP	
  2015	
   19	
  
We use it all the time
namespace ApplicationController;!
!
use ZendMvcControllerAbstractActionController;!
use ZendViewModelViewModel;!
!
Class IndexController extends AbstractActionController!
{!
public function indexAction()!
{!
/** @var VendorVendorService $vendor */!
$vendor = $this->serviceLocator->get('VendorVendorService');!
!
$view = new ViewModel();!
return $view;!
}!
}	
  
LonestarPHP	
  2015	
   20	
  
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	
  
LonestarPHP	
  2015	
   21	
  
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	
  instanOated	
  directly,	
  they	
  must	
  be	
  extended	
  
LonestarPHP	
  2015	
   22	
  
The Employee Class
LonestarPHP	
  2015	
   23	
  
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
LonestarPHP	
  2015	
   24	
  
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
<?php!
// Cannot do this. This will throw the following error:!
// Fatal error: Cannot instantiate abstract class Employee!
$employee = new Employee(); !
// We can do this though!!
$manager = new Manager(); !
// Name is protected, so we can't do this. This throws:!
// 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();	
  
LonestarPHP	
  2015	
   25	
  
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	
  funcOonality	
  
between	
  disparate	
  classes	
  
LonestarPHP	
  2015	
   26	
  
Composition over Inheritance
LonestarPHP	
  2015	
   27	
  
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	
  funcOonality	
  
LonestarPHP	
  2015	
   28	
  
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);!
}	
  
LonestarPHP	
  2015	
   29	
  
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;!
}!
}	
  
LonestarPHP	
  2015	
   30	
  
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	
  ImplementaOon,	
  so	
  can	
  lead	
  to	
  
code	
  duplicaOon	
  
LonestarPHP	
  2015	
   31	
  
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	
  should	
  need	
  to	
  extend	
  a	
  Slugger	
  class	
  just	
  to	
  
generate	
  slugs.	
  	
  
LonestarPHP	
  2015	
   32	
  
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;!
}	
  
LonestarPHP	
  2015	
   33	
  
Taking Advantage of OOP
LonestarPHP	
  2015	
   34	
  
Coupling
LonestarPHP	
  2015	
   35	
  
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	
  
LonestarPHP	
  2015	
   36	
  
<?php!
!
namespace ApplicationController;!
!
use ZendMvcControllerAbstractActionController;!
use ZendViewModelViewModel;!
!
class MapController extends AbstractActionController!
{!
public function indexAction()!
{!
// Position is an array with a Latitude and Longitude object!
$position = $this->getServiceLocator()->get('MapService’)!
->getLatLong('123 Main Street', 'Defiance', 'OH');!
echo $position->latitude->getPoint();!
}!
}	
  
LonestarPHP	
  2015	
   37	
  
Law of Demeter
LonestarPHP	
  2015	
   38	
  
Dependency Injection
LonestarPHP	
  2015	
   39	
  
What is Dependency Injection?
•  InjecOng	
  dependencies	
  into	
  classes,	
  instead	
  of	
  having	
  the	
  class	
  create	
  
it	
  
•  Allows	
  for	
  much	
  easier	
  tesOng	
  
•  Allows	
  for	
  a	
  much	
  easier	
  Ome	
  swapping	
  out	
  code	
  
•  Reduces	
  the	
  coupling	
  that	
  happens	
  between	
  classes	
  
LonestarPHP	
  2015	
   40	
  
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);!
}!
}	
  
LonestarPHP	
  2015	
   41	
  
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);!
}!
}!
!
	
  
LonestarPHP	
  2015	
   42	
  
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);!
}!
}!
	
  
LonestarPHP	
  2015	
   43	
  
Single Responsibility Principle
LonestarPHP	
  2015	
   44	
  
Single Responsibility Principle
•  Every	
  class	
  should	
  have	
  a	
  single	
  responsibility,	
  and	
  that	
  responsibility	
  
should	
  be	
  encapsulated	
  in	
  that	
  class	
  
LonestarPHP	
  2015	
   45	
  
What is a Responsibility?
•  Responsibility	
  is	
  a	
  “Reason	
  To	
  Change”	
  –	
  Robert	
  C.	
  MarOn	
  
•  By	
  having	
  more	
  than	
  one	
  “Reason	
  to	
  Change”,	
  code	
  is	
  harder	
  to	
  
maintain	
  and	
  becomes	
  coupled	
  
•  Since	
  the	
  class	
  is	
  coupled	
  to	
  mulOple	
  responsibiliOes,	
  it	
  becomes	
  
harder	
  for	
  the	
  class	
  to	
  adapt	
  to	
  any	
  one	
  responsibility	
  
	
  
LonestarPHP	
  2015	
   46	
  
An Example
/**
* Create a new invoice instance.
*
* @param LaravelCashierContractsBillable $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 SymfonyComponentHttpFoundationResponse
*/
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;
}
LonestarPHP	
  2015	
   47	
  
hFps://github.com/laravel/cashier/blob/master/src/Laravel/Cashier/Invoice.php	
  
Why is this Bad?
•  This	
  single	
  class	
  has	
  the	
  following	
  responsibiliOes:	
  
•  GeneraOng	
  totals	
  for	
  the	
  invoice	
  (including	
  discounts/coupons)	
  
•  GeneraOng	
  an	
  HTML	
  View	
  of	
  the	
  invoice	
  (Invoice::view())	
  
•  GeneraOng	
  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	
  
LonestarPHP	
  2015	
   48	
  
How to Improve
•  Change	
  responsibility	
  to	
  just	
  building	
  the	
  invoice	
  data	
  
•  Move	
  the	
  ‘output’	
  stuff	
  to	
  other	
  classes	
  
LonestarPHP	
  2015	
   49	
  
Unit Testing
LonestarPHP	
  2015	
   50	
  
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	
  InjecOon	
  means	
  you	
  only	
  mock	
  what	
  you	
  need	
  for	
  that	
  
test	
  
•  Single	
  Responsibility	
  means	
  your	
  test	
  should	
  be	
  short	
  and	
  sweet	
  
•  Easier	
  tesOng	
  leads	
  to	
  more	
  tesOng	
  
LonestarPHP	
  2015	
   51	
  
Final Thoughts
LonestarPHP	
  2015	
   52	
  
We can make 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	
  
LonestarPHP	
  2015	
   53	
  
Here’s a cute dog instead
LonestarPHP	
  2015	
   54	
  
Thank You!
hFp://ctankersley.com	
  
chris@ctankersley.com	
  
@dragonmantank	
  
	
  
hFps://joind.in/13542	
  
LonestarPHP	
  2015	
   55	
  

OOP is more than Cars and Dogs

  • 1.
    OOP is MoreThan Cats and Dogs Chris  Tankersley   LonestarPHP  2015   LonestarPHP  2015   1  
  • 2.
    Who Am I • PHP  Programmer  for  over  10  years   •  Work/know  a  lot  of  different   languages,  even  COBOL   •  Primarily  do  Zend  Framework  2   •  hFps://github.com/dragonmantank   LonestarPHP  2015   2  
  • 3.
    Quick Vocabulary Lesson • Class  –  DefiniOon  of  code   •  Object  –  InstanOaOon  of  a  Class   •  Member  –  Variable  belonging  to  a  class   •  Method  –  FuncOon  belonging  to  a  class   There  will  be  more  as  we  go  along   LonestarPHP  2015   3  
  • 4.
    LonestarPHP  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; } }
  • 5.
    Object •  <?php! •  $manager=new Manager();! •  // ^! •  // |! •  // `--- This is the Object   LonestarPHP  2015   5  
  • 6.
    Why are weusing OOP? LonestarPHP  2015   6  
  • 7.
    Let’s count thereasons •  Because  we’re  told  to,  procedural  programming  leads  to  spagheX   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   LonestarPHP  2015   7  
  • 8.
    Getting OOP Rightcan be Complicated •  Animals  can  speak,  and  have  legs  and  fur.  Let’s  make  objects  based   on  that   •  Dogs  are  animals,  and  so  are  cats   •  What  about  Fish?   •  Cars  have  doors,  engines,  and  colors.  They  only  go  so  fast.  Let’s   model  that   •  Motorcycles  aren’t  Cars,  so  let’s  refactor  Cars   •  Holy  crap  there  are  a  lot  of  engines…  and  wheels…     LonestarPHP  2015   8  
  • 9.
    Can a Doghave Wheels? •  Discuss  (or  listen  to  me  talk  some  more)   LonestarPHP  2015   9  
  • 10.
  • 11.
    What we’re alltaught •  Classes  are  “things”  in  the  real  world   •  We  should  construct  class  members  based  on  AFributes   •  Number  of  wheels   •  Sound  it  makes   •  We  should  construct  class  methods  based  on  “AcOons”   •  Running   •  Speaking   •  Jumping   LonestarPHP  2015   11  
  • 12.
    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  Ome   LonestarPHP  2015   12  
  • 13.
    Where I LearnedIt LonestarPHP  2015   13  
  • 14.
    Our Structure LonestarPHP  2015   14   Employee   Manager   ScienOst   Laborer  
  • 15.
    The Employee Class LonestarPHP  2015   15   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; } }
  • 16.
    The Manager Class LonestarPHP  2015   16   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; } }
  • 17.
    The Scientist Class LonestarPHP  2015   17   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; } }
  • 18.
    The Laborer Class LonestarPHP  2015   18   class Laborer extends Employee { }
  • 19.
    What does thisteach 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   LonestarPHP  2015   19  
  • 20.
    We use itall the time namespace ApplicationController;! ! use ZendMvcControllerAbstractActionController;! use ZendViewModelViewModel;! ! Class IndexController extends AbstractActionController! {! public function indexAction()! {! /** @var VendorVendorService $vendor */! $vendor = $this->serviceLocator->get('VendorVendorService');! ! $view = new ViewModel();! return $view;! }! }   LonestarPHP  2015   20  
  • 21.
    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   LonestarPHP  2015   21  
  • 22.
    How to useit •  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  instanOated  directly,  they  must  be  extended   LonestarPHP  2015   22  
  • 23.
    The Employee Class LonestarPHP  2015   23   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; } }
  • 24.
    The Manager Class LonestarPHP  2015   24   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; } }
  • 25.
    An Example <?php! // Cannotdo this. This will throw the following error:! // Fatal error: Cannot instantiate abstract class Employee! $employee = new Employee(); ! // We can do this though!! $manager = new Manager(); ! // Name is protected, so we can't do this. This throws:! // 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();   LonestarPHP  2015   25  
  • 26.
    Why can InheritanceBe 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  funcOonality   between  disparate  classes   LonestarPHP  2015   26  
  • 27.
  • 28.
    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  funcOonality   LonestarPHP  2015   28  
  • 29.
    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);! }   LonestarPHP  2015   29  
  • 30.
    Interface Implementation class Employeeimplements 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;! }! }   LonestarPHP  2015   30  
  • 31.
    This is Goodand 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  ImplementaOon,  so  can  lead  to   code  duplicaOon   LonestarPHP  2015   31  
  • 32.
    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  should  need  to  extend  a  Slugger  class  just  to   generate  slugs.     LonestarPHP  2015   32  
  • 33.
    Avoid Code-Duplication withTraits 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;! }   LonestarPHP  2015   33  
  • 34.
    Taking Advantage ofOOP LonestarPHP  2015   34  
  • 35.
  • 36.
    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   LonestarPHP  2015   36  
  • 37.
    <?php! ! namespace ApplicationController;! ! use ZendMvcControllerAbstractActionController;! useZendViewModelViewModel;! ! class MapController extends AbstractActionController! {! public function indexAction()! {! // Position is an array with a Latitude and Longitude object! $position = $this->getServiceLocator()->get('MapService’)! ->getLatLong('123 Main Street', 'Defiance', 'OH');! echo $position->latitude->getPoint();! }! }   LonestarPHP  2015   37  
  • 38.
  • 39.
  • 40.
    What is DependencyInjection? •  InjecOng  dependencies  into  classes,  instead  of  having  the  class  create   it   •  Allows  for  much  easier  tesOng   •  Allows  for  a  much  easier  Ome  swapping  out  code   •  Reduces  the  coupling  that  happens  between  classes   LonestarPHP  2015   40  
  • 41.
    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);! }! }   LonestarPHP  2015   41  
  • 42.
    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);! }! }! !   LonestarPHP  2015   42  
  • 43.
    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);! }! }!   LonestarPHP  2015   43  
  • 44.
  • 45.
    Single Responsibility Principle • Every  class  should  have  a  single  responsibility,  and  that  responsibility   should  be  encapsulated  in  that  class   LonestarPHP  2015   45  
  • 46.
    What is aResponsibility? •  Responsibility  is  a  “Reason  To  Change”  –  Robert  C.  MarOn   •  By  having  more  than  one  “Reason  to  Change”,  code  is  harder  to   maintain  and  becomes  coupled   •  Since  the  class  is  coupled  to  mulOple  responsibiliOes,  it  becomes   harder  for  the  class  to  adapt  to  any  one  responsibility     LonestarPHP  2015   46  
  • 47.
    An Example /** * Createa new invoice instance. * * @param LaravelCashierContractsBillable $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 SymfonyComponentHttpFoundationResponse */ 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; } LonestarPHP  2015   47   hFps://github.com/laravel/cashier/blob/master/src/Laravel/Cashier/Invoice.php  
  • 48.
    Why is thisBad? •  This  single  class  has  the  following  responsibiliOes:   •  GeneraOng  totals  for  the  invoice  (including  discounts/coupons)   •  GeneraOng  an  HTML  View  of  the  invoice  (Invoice::view())   •  GeneraOng  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   LonestarPHP  2015   48  
  • 49.
    How to Improve • Change  responsibility  to  just  building  the  invoice  data   •  Move  the  ‘output’  stuff  to  other  classes   LonestarPHP  2015   49  
  • 50.
  • 51.
    This is nota 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  InjecOon  means  you  only  mock  what  you  need  for  that   test   •  Single  Responsibility  means  your  test  should  be  short  and  sweet   •  Easier  tesOng  leads  to  more  tesOng   LonestarPHP  2015   51  
  • 52.
  • 53.
    We can makea 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   LonestarPHP  2015   53  
  • 54.
    Here’s a cutedog instead LonestarPHP  2015   54  
  • 55.
    Thank You! hFp://ctankersley.com   chris@ctankersley.com   @dragonmantank     hFps://joind.in/13542   LonestarPHP  2015   55