OOP is more than Cars and Dogs

524 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!

Published in: Software
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
524
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

OOP is more than Cars and Dogs

  1. 1. OOP is More Than Cats and Dogs Chris  Tankersley   LonestarPHP  2015   LonestarPHP  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   •  hFps://github.com/dragonmantank   LonestarPHP  2015   2  
  3. 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. 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. 5. Object •  <?php! •  $manager= new Manager();! •  // ^! •  // |! •  // `--- This is the Object   LonestarPHP  2015   5  
  6. 6. Why are we using OOP? LonestarPHP  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   LonestarPHP  2015   7  
  8. 8. 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  
  9. 9. Can a Dog have Wheels? •  Discuss  (or  listen  to  me  talk  some  more)   LonestarPHP  2015   9  
  10. 10. Inheritance LonestarPHP  2015   10  
  11. 11. 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  
  12. 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. 13. Where I Learned It LonestarPHP  2015   13  
  14. 14. Our Structure LonestarPHP  2015   14   Employee   Manager   ScienOst   Laborer  
  15. 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. 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. 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. 18. The Laborer Class LonestarPHP  2015   18   class Laborer extends Employee { }
  19. 19. 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  
  20. 20. 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  
  21. 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. 22. 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  
  23. 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. 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. 25. 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  
  26. 26. 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  
  27. 27. Composition over Inheritance LonestarPHP  2015   27  
  28. 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. 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. 30. 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  
  31. 31. 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  
  32. 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. 33. 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  
  34. 34. Taking Advantage of OOP LonestarPHP  2015   34  
  35. 35. Coupling LonestarPHP  2015   35  
  36. 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. 37. <?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  
  38. 38. Law of Demeter LonestarPHP  2015   38  
  39. 39. Dependency Injection LonestarPHP  2015   39  
  40. 40. 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  
  41. 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. 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. 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. 44. Single Responsibility Principle LonestarPHP  2015   44  
  45. 45. Single Responsibility Principle •  Every  class  should  have  a  single  responsibility,  and  that  responsibility   should  be  encapsulated  in  that  class   LonestarPHP  2015   45  
  46. 46. 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  
  47. 47. 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  
  48. 48. 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  
  49. 49. How to Improve •  Change  responsibility  to  just  building  the  invoice  data   •  Move  the  ‘output’  stuff  to  other  classes   LonestarPHP  2015   49  
  50. 50. Unit Testing LonestarPHP  2015   50  
  51. 51. 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  
  52. 52. Final Thoughts LonestarPHP  2015   52  
  53. 53. 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  
  54. 54. Here’s a cute dog instead LonestarPHP  2015   54  
  55. 55. Thank You! hFp://ctankersley.com   chris@ctankersley.com   @dragonmantank     hFps://joind.in/13542   LonestarPHP  2015   55  

×