Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

OOP Is More Than Cars and Dogs

436 views

Published on

When developers are introduced to Object Oriented Programming, one of the first things that happens is that they are taught that nouns turn into objects, verbs into methods, and Dog is a subclass of Animal. OOP is more than just turning things into classes and objects and showing that both Boats and Cars have motors, and that Dogs and Cats both speak(). Let's look at OOP in real world settings and go beyond cars and dogs, and see how to use Object Oriented Programming properly in PHP. Traits, Composition, Inheritance, none of it is off limits! (No animals were harmed in preparation for this talk, though there was mention of showing how a dog can have wheels. And yes, the title is supposed to be Cars and Dogs.)

Published in: Technology
  • Be the first to comment

OOP Is More Than Cars and Dogs

  1. 1. OOP is More Than Cars and Dogs Chris  Tankersley   MadisonPHP  2015   MadisonPHP  2015   1  
  2. 2. Who Am I •  PHP  Programmer  for  over  10  years   •  Work/know  a  lot  of  different   languages,  even  COBOL   •  Primarily  do  Zend  Framework  2   •  hGps://github.com/dragonmantank   MadisonPHP  2015   2  
  3. 3. Quick Vocabulary Lesson •  Class  –  DefiniPon  of  code   •  Object  –  InstanPaPon  of  a  Class   •  Member  –  Variable  belonging  to  a  class   •  Method  –  FuncPon  belonging  to  a  class   There  will  be  more  as  we  go  along   MadisonPHP  2015   3  
  4. 4. MadisonPHP  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. 5. Object <?php! ! $manager= new Manager();! // ^! // |! // `--- This is the Object   MadisonPHP  2015   5  
  6. 6. Why are we using OOP? MadisonPHP  2015   6  
  7. 7. 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   MadisonPHP  2015   7  
  8. 8. Getting OOP Right is Complicated MadisonPHP  2015   8  
  9. 9. MadisonPHP  2015   9  
  10. 10. MadisonPHP  2015   10  
  11. 11. MadisonPHP  2015   11  
  12. 12. MadisonPHP  2015   12  
  13. 13. MadisonPHP  2015   13  
  14. 14. MadisonPHP  2015   14  
  15. 15. Can a Dog have Wheels? MadisonPHP  2015   15  
  16. 16. Inheritance MadisonPHP  2015   16  
  17. 17. What we’re all taught •  Classes  are  “things”  in  the  real  world   •  We  should  construct  class  members  based  on  AGributes   •  Number  of  wheels   •  Sound  it  makes   •  We  should  construct  class  methods  based  on  “AcPons”   •  Running   •  Speaking   •  Jumping   MadisonPHP  2015   17  
  18. 18. 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  Pme   MadisonPHP  2015   18  
  19. 19. Where I Learned It MadisonPHP  2015   19  
  20. 20. Our Structure MadisonPHP  2015   20   Employee   Manager   ScienPst   Laborer  
  21. 21. The Employee Class MadisonPHP  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; } }
  22. 22. The Manager Class MadisonPHP  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; } }
  23. 23. The Scientist Class MadisonPHP  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; } }
  24. 24. The Laborer Class MadisonPHP  2015   24   class Laborer extends Employee { }
  25. 25. 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   MadisonPHP  2015   25  
  26. 26. 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;! }! }   MadisonPHP  2015   26  
  27. 27. 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   MadisonPHP  2015   27  
  28. 28. 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  instanPated  directly,  they  must  be  extended   MadisonPHP  2015   28  
  29. 29. The Employee Class MadisonPHP  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; } }
  30. 30. The Manager Class MadisonPHP  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; } }
  31. 31. 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();   MadisonPHP  2015   31  
  32. 32. 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  funcPonality   between  disparate  classes   MadisonPHP  2015   32  
  33. 33. Composition over Inheritance MadisonPHP  2015   33  
  34. 34. 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  funcPonality   MadisonPHP  2015   34  
  35. 35. 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);! }   MadisonPHP  2015   35  
  36. 36. 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;! }! }   MadisonPHP  2015   36  
  37. 37. 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  ImplementaPon,  so  can  lead  to   code  duplicaPon   MadisonPHP  2015   37  
  38. 38. 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.     MadisonPHP  2015   38  
  39. 39. 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;! }   MadisonPHP  2015   39  
  40. 40. Taking Advantage of OOP MadisonPHP  2015   40  
  41. 41. Coupling MadisonPHP  2015   41  
  42. 42. 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   MadisonPHP  2015   42  
  43. 43. 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();! }! }   MadisonPHP  2015   43  
  44. 44. Law of Demeter MadisonPHP  2015   44  
  45. 45. Dependency Injection MadisonPHP  2015   45  
  46. 46. What is Dependency Injection? •  InjecPng  dependencies  into  classes,  instead  of  having  the  class  create   it   •  Allows  for  much  easier  tesPng   •  Allows  for  a  much  easier  Pme  swapping  out  code   •  Reduces  the  coupling  that  happens  between  classes   MadisonPHP  2015   46  
  47. 47. 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);! }! }   MadisonPHP  2015   47  
  48. 48. 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);! }! }! !   MadisonPHP  2015   48  
  49. 49. 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);! }! }!   MadisonPHP  2015   49  
  50. 50. Single Responsibility Principle MadisonPHP  2015   50  
  51. 51. Single Responsibility Principle •  Every  class  should  have  a  single  responsibility,  and  that  responsibility   should  be  encapsulated  in  that  class   MadisonPHP  2015   51  
  52. 52. What is a Responsibility? •  Responsibility  is  a  “Reason  To  Change”  –  Robert  C.  MarPn   •  By  having  more  than  one  “Reason  to  Change”,  code  is  harder  to   maintain  and  becomes  coupled   •  Since  the  class  is  coupled  to  mulPple  responsibiliPes,  it  becomes   harder  for  the  class  to  adapt  to  any  one  responsibility     MadisonPHP  2015   52  
  53. 53. 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; } MadisonPHP  2015   53   hGps://github.com/laravel/cashier/blob/master/src/Laravel/Cashier/Invoice.php  
  54. 54. Why is this Bad? •  This  single  class  has  the  following  responsibiliPes:   •  GeneraPng  totals  for  the  invoice  (including  discounts/coupons)   •  GeneraPng  an  HTML  View  of  the  invoice  (Invoice::view())   •  GeneraPng  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   MadisonPHP  2015   54  
  55. 55. How to Improve •  Change  responsibility  to  just  building  the  invoice  data   •  Move  the  ‘output’  stuff  to  other  classes   MadisonPHP  2015   55  
  56. 56. Unit Testing MadisonPHP  2015   56  
  57. 57. [Could  not  afford  licensing  fee  for  Grumpy  TesPng  Picture]   MadisonPHP  2015   57  
  58. 58. 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  InjecPon  means  you  only  mock  what  you  need  for  that   test   •  Single  Responsibility  means  your  test  should  be  short  and  sweet   •  Easier  tesPng  leads  to  more  tesPng   MadisonPHP  2015   58  
  59. 59. Final Thoughts MadisonPHP  2015   59  
  60. 60. 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   MadisonPHP  2015   60  
  61. 61. Here’s a cute dog instead MadisonPHP  2015   61  
  62. 62. Additional Resources •  Clean  Code  –  Robert  C.  MarPn   •  PHP  Objects,  PaGerns,  and  PracPce  –  MaG  Zandstra   MadisonPHP  2015   62  
  63. 63. Thank You! hGp://ctankersley.com   chris@ctankersley.com   @dragonmantank     hGps://joind.in/16010   MadisonPHP  2015   63  
  64. 64. Photos •  Slide  9  -­‐  hGp://bit.ly/1dkaoxS   •  Slide  10  -­‐  hGp://bit.ly/1c4Gc8z   •  Slide  11  -­‐  hGp://bit.ly/1R3isBp   •  Slide  12  -­‐  hGp://bit.ly/1ScEWRZ   •  Slide  13  -­‐  hGp://bit.ly/1Bc0qUv   •  Slide  14  -­‐  hGp://bit.ly/1ILhfNV   •  Slide  15  -­‐  hGp://bit.ly/1SeekA7     MadisonPHP  2015   64  

×