1 / 28

SOLID PHP & Code Smell Wrap-Up

SOLID PHP & Code Smell Wrap-Up. LSP: Liskov substitution principle ISP: Interface segregation principle DIP: Dependency inversion principle. SOLID PHP & Code Smell Wrap-Up. LSP: Liskov substitution principle DIP: Dependency inversion principle ISP: Interface segregation principle.

elana
Download Presentation

SOLID PHP & Code Smell Wrap-Up

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. SOLID PHP & Code Smell Wrap-Up LSP: Liskov substitution principle ISP: Interface segregation principle DIP: Dependency inversion principle

  2. SOLID PHP & Code Smell Wrap-Up LSP: Liskov substitution principle DIP: Dependency inversion principle ISP: Interface segregation principle

  3. Review • SOLID is an acronym for a set of design principles by Robert “Uncle Bob” Martin • SRP: Single Responsibility principle – Objects should only have one responsibility • OCP: Open/closed principle – Objects open for extension but closed for modification

  4. LSP: Liskov substitution principle • Objects should always be able to stand-in for their ancestors • Named after Barbara Liskov who first introduced the principal

  5. DIP: Dependency inversion principle • Define interfaces from the bottom-up, not top-down • Depend on interfaces, not on concrete classes

  6. ISP: Interface segregation principle • “many client specific interfaces are better than one general purpose interface.”

  7. LSP Example: Rectangle & Square • The Rectangle and Square are the “standard” example of an LSP problem. • A Square IS-A Rectangle which happens to have the same width and height: Square IS-A Rectangle

  8. LSP Example: Rectangle & Square • Lets look at an implementation and unit test • Squares don’t BEHAVE like rectangles, so they violate LSP BEHAVIOUR Square Rectangle

  9. More Obvious LSP Violations class FooMapper{ function fetchAll() { return array( 'a588ea995c5c74827a24d466d14a72101'=>'Alpha', 'z4c853bae4a5e427a8d6b9bf33140bb2e'=>'Omega'); } } class BarMapperextends FooMapper { function fetchAll() { $result = new stdClass(); $result->a588ea995c5c74827a24d466d14a72101 = 'Alpha'; $result->z4c853bae4a5e427a8d6b9bf33140bb2e = 'Omega'; return $result; } }

  10. More Obvious LSP Violations class FooView { function display(FooModel $foo) { /* ... */ } } class BarViewextends FooView { function display(BarModel $bar) { /* ... */ } }

  11. More Obvious LSP Violations • Removing functionality from an ancestor: class DecoyDuckextends Duck { function fly() { throw new Exception( "Decoy ducks can't fly!"); } }

  12. Is this an LSP Violation? class Foo { function getMapper() { return new FooMapper(); } } class Bar extends Foo { function getMapper() { return new BarMapper(); } }

  13. Preventing LSP Violations • Design by Contract with Unit Tests • Think in terms of BEHAVES-LIKE instead of IS-A when creating subclasses • Don’t remove functionality from ancestors

  14. Preventing LSP Violations • Method parameters should be the same or less restrictive in what they will accept (invariant or contravariant) • Method return values should be the same or more restrictive in what is returned (invariant or covariant)

  15. Smells like an LSP Violation • Any time you need to know the type of an object (instanceof, is_a, etc) • When the parameters or return type of an overridden method are different from its ancestor • Throwing new exceptions

  16. DIP: What is Inversion? Conventional MVC Dependencies: Controller Model View Storage

  17. DIP: What is Inversion? Inverted MVC Dependencies: Model Service Interface View Service Interface Controller Storage Service Interface Model View Storage

  18. DIP Concepts • Concrete classes only have dependencies to interfaces • High level components build interfaces for the services they need • Low level components depend on those high level service interfaces

  19. Evolving towards the DIP class FooControllerConventional { function indexView() { $model = new FooModel(); $viewData = $model->fetchAll(); $view = new FooView(); $view->render($viewData); } }

  20. Evolving towards the DIP class FooControllerDI { private $_model; private $_view; function __construct(FooModel $model, FooView $view) { $this->_model = $model; $this->_view = $view; } function indexView() { $viewData = $this->_model->fetchAll(); $this->_view->render($viewData); } }

  21. Evolving towards the DIP interface ModelServiceInterface { function fetchAll(); //… Other required methods } interface ViewServiceInterface { function render($viewData); //… Other required methods }

  22. Evolving towards the DIP class FooControllerDIP { private $_model; private $_view; function __construct(ModelServiceInterface $model, ViewServiceInterface$view) { $this->_model = $model; $this->_view = $view; } function indexView() { $viewData = $this->_model->fetchAll(); $this->_view->render($viewData); } }

  23. Smells like a DIP Violation • Any dependency by one class on another concrete class: “Hard Dependency Smell”

  24. Interface Segregation Principle • Useful for “fat” classes. These classes: • May violate SRP • May have an “extra” method for a specific client • May have one responsibility which can be further segregated

  25. ISP Example: User Model class UserModel { /** * @param string $userId * @param string $password * @return string Authentication Token; empty string on failure */ function doLogin($userId, $password) {} /** * @param string $token * @returnbool */ function authenticate($token) {} } Most clients just want to authenticate. Only the login controller uses doLogin().

  26. ISP Example: User Model interface UserLoginClient { function doLogin($userId, $password); } interface UserAuthenticationClient { function authenticate($token); }

  27. Smells Like an ISP Violation • Fat Classes, “God Objects” • Methods only used by a few clients but pollute the interface used by all clients

  28. Thanks Folks! • Thanks for joining me for the SOLID wrap up! • If we have time, I have some code we can refactor to play with LSP, DIP and ISP • Slides and code will be posted shortly • Next week: CakePHP and Facebook Apps!

More Related