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 Then Cars and Dogs - Midwest PHP 2017

234 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: Technology
  • Be the first to comment

OOP Is More Then Cars and Dogs - Midwest PHP 2017

  1. 1. OOP is More Than Cars and Dogs Chris Tankersley Midwest PHP 2017 Midwest PHP 2017 1
  2. 2. Quick Vocabulary Lesson • Class – Definition of code • Object – Instantiation of a Class • Member/Property – Variable belonging to a class • Method – Function belonging to a class There will be more as we go along Midwest PHP 2017 2
  3. 3. Midwest PHP 2017 3 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; } }
  4. 4. Object <?php $manager= new Manager(); // ^ // | // `--- This is the Object Midwest PHP 2017 4
  5. 5. Why are we using OOP? Midwest PHP 2017 5
  6. 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 Midwest PHP 2017 6
  7. 7. Getting OOP Right is Complicated Midwest PHP 2017 7
  8. 8. Midwest PHP 2017 8
  9. 9. Midwest PHP 2017 9
  10. 10. Midwest PHP 2017 10
  11. 11. Midwest PHP 2017 11
  12. 12. Midwest PHP 2017 12
  13. 13. Midwest PHP 2017 13
  14. 14. Can a Dog have Wheels? Midwest PHP 2017 14
  15. 15. Inheritance Midwest PHP 2017 15
  16. 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 Midwest PHP 2017 16
  17. 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 Midwest PHP 2017 17
  18. 18. Where I Learned It Midwest PHP 2017 18
  19. 19. Our Structure Midwest PHP 2017 19 Employee Manager Scientist Laborer
  20. 20. The Employee Class Midwest PHP 2017 20 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; } }
  21. 21. The Manager Class Midwest PHP 2017 21 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; } }
  22. 22. The Scientist Class Midwest PHP 2017 22 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; } }
  23. 23. The Laborer Class Midwest PHP 2017 23 class Laborer extends Employee { }
  24. 24. 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 Midwest PHP 2017 24
  25. 25. 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; } } Midwest PHP 2017 25
  26. 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 Midwest PHP 2017 26
  27. 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 Midwest PHP 2017 27
  28. 28. The Employee Class Midwest PHP 2017 28 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; } }
  29. 29. The Manager Class Midwest PHP 2017 29 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; } }
  30. 30. 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(); Midwest PHP 2017 30
  31. 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 Midwest PHP 2017 31
  32. 32. Composition over Inheritance Midwest PHP 2017 32
  33. 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 Midwest PHP 2017 33
  34. 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); } Midwest PHP 2017 34
  35. 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; } } Midwest PHP 2017 35
  36. 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 Midwest PHP 2017 36
  37. 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. Midwest PHP 2017 37
  38. 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; } Midwest PHP 2017 38
  39. 39. Taking Advantage of OOP Midwest PHP 2017 39
  40. 40. Coupling Midwest PHP 2017 40
  41. 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 Midwest PHP 2017 41
  42. 42. 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(); } } Midwest PHP 2017 42
  43. 43. Law of Demeter Midwest PHP 2017 43
  44. 44. Dependency Injection Midwest PHP 2017 44
  45. 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 Midwest PHP 2017 45
  46. 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); } } Midwest PHP 2017 46
  47. 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); } } Midwest PHP 2017 47
  48. 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); } } Midwest PHP 2017 48
  49. 49. Single Responsibility Principle Midwest PHP 2017 49
  50. 50. Single Responsibility Principle • Every class should have a single responsibility, and that responsibility should be encapsulated in that class Midwest PHP 2017 50
  51. 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 Midwest PHP 2017 51
  52. 52. 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; } Midwest PHP 2017 52 https://github.com/laravel/cashier/blob/5.0/src/Laravel/Cashier/Invoice.php
  53. 53. 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 Midwest PHP 2017 53
  54. 54. How to Improve • Change responsibility to just building the invoice data • Move the ‘output’ stuff to other classes Midwest PHP 2017 54
  55. 55. Unit Testing Midwest PHP 2017 55
  56. 56. Test Driven Development • Write your tests • Watch them fail • Write code to make the tests pass • Feel better! (and refactor) Midwest PHP 2017 56
  57. 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 Midwest PHP 2017 57
  58. 58. Final Thoughts Midwest PHP 2017 58
  59. 59. We can make a dog with wheels! • Abstract class for Animal • Class for Dog that extends Animal • Trait for Wheels • With the correct methodology, we could even unit test this As in the real world, we can now represent a crippled dog Midwest PHP 2017 59
  60. 60. Here’s a cute dog instead Midwest PHP 2017 60
  61. 61. Additional Resources • Clean Code – Robert C. Martin • PHP Objects, Patterns, and Practice – Matt Zandstra Midwest PHP 2017 61
  62. 62. Thank You! • Software Engineer for InQuest • Author of “Docker for Developers” • https://leanpub.com/dockerfordevs • Co-Host of “Jerks Talk Games” • http://jerkstalkgames • http://ctankersley.com • chris@ctankersley.com • @dragonmantank SunshinePHP 2017 62
  63. 63. 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 • Slide 15 - http://bit.ly/1SeekA7 Midwest PHP 2017 63

×