Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OOP for Drupal Developers

Lorna Mitchell
September 29, 2014

OOP for Drupal Developers

Introduction to Object-Oriented PHP for DrupalCon Amsterdam

Lorna Mitchell

September 29, 2014
Tweet

More Decks by Lorna Mitchell

Other Decks in Technology

Transcript

  1. OOP Glossary • methods these are functions. Seriously • properties

    these are variables • class recipe for making an object • object cool thing with its own properties and methods
  2. Encapsulation In OOP: • array indexes become “properties” • functions

    lose their prefix and become “methods” An object contains both data and functionality
  3. Encapsulation Imagine an array of data $date = array("hours" =>

    "14", "minutes" => "36", "timezone" => "Europe/Amsterdam"); And some functions date_get_timestamp($date); date_get_time($date); date_get_datetime_in_timezone($date, $tz);
  4. Autoloading Code in classes can be autoloaded. This means: •

    you will never write another require() statement • only the code actually needed will ever be parsed
  5. Prerequisites for Autoloading • one class per file • very

    predictable mapping from namespaced classname to file location • e.g. \MyLib\User lives in lib/MyLib/User.php For more details, see PSR4: http://www.php-fig.org/psr/psr-4/
  6. Write an Autoloader Write a function which accepts the classname

    and includes the relevant file. To tell PHP about your autoloader: spl_autoload_register("my_autoload_func");
  7. Extendable We can take an object, and just change one

    bit or add something, without copy pasting. The keyword is “inheritance”
  8. Inheritance Take this ClickableButton class and make it go ping

    when clicked. class PingingButton extends ClickableButton Our new class gets everything that was in ClickableButton and we can add/override as we wish
  9. Pluggable Code expecting one type of object can easily accept

    a similar one. We can extend or replace objects without changing the code that handles it.
  10. PHP User Class Start by declaring the class and its

    properties … 1 class User { 2 protected $username; 3 protected $email;
  11. PHP User Class … next the constructor … 1 public

    function __construct($username) { 2 // lookup table for people's details 3 $people = [ 4 "lornajane" => "[email protected]", 5 "crell" => "larry@...", 6 "emmajanehw" => "emma@..." 7 ]; 8 9 $this->username = $username; 10 $this->email = $people[$username]; 11 12 }
  12. PHP User Class … and a couple of other methods

    1 public function getUsername() { 2 return $this->username; 3 } 4 5 public function getGravatar() { 6 $url = "http://www.gravatar.com/avatar/" 7 . md5($this->email); 8 return "<img src=\"$url\">"; 9 } 10 }
  13. How to Use a Class First we need to require

    or autoload the code. Then we instantiate the object.
  14. Instantiate a User Object Create an object by using the

    new keyword $user = new User("lornajane");
  15. User Object in a Template This is what I have

    in my template file <?=$user->getGravatar()?> Hi, <?=$user->getUsername()?>
  16. Project Overview . ├── inc │ └── User.php ├── public

    │ └── index.php ├── README.md └── templates ├── footer.php ├── greet.php ├── header.php └── login.php
  17. Inheritance We have a User class. How about something a

    little more specific? 1 class AdminUser extends User { 2 public function getUsername() { 3 $name = parent::getUsername(); 4 return $name . " (admin)"; 5 } 6 }
  18. Use the Admin Class If the user ticked the box,

    we stored that too 1 if($_SESSION['admin']) { 2 $user = new AdminUser($_SESSION['username']); 3 } else { 4 $user = new User($_SESSION['username']); 5 }
  19. What About StdClass? The StdClass class is just the parent

    of all other objects in PHP It’s better to declare a class for a specific use
  20. Namespaces We change class declarations and rename files to match

    inc/User.php becomes inc/User/User.php namespace User; class User { inc/AdminUser.php becomes inc/User/Admin.php namespace User; class Admin extends User {
  21. Project Overview . ├── inc │ ├── Animal │ │

    └── Cat.php │ └── User │ ├── Admin.php │ └── User.php ├── public │ └── index.php ├── README.md └── templates └── ...
  22. Namespaces The autoloader needs to change as well 1 spl_autoload_register(function

    ($classname) { 2 require __DIR__ . '/../inc/' 3 . str_replace('\\', DIRECTORY_SEPARATOR, $classname) 4 . '.php'; 5 });
  23. Namespaces We also need to give the qualified name of

    the object when instantiating it: $user = new \User\User("lornajane");
  24. Namespaces New classes can go into new namespaces 1 namespace

    Animal; 2 3 class Cat { 4 protected $username; 5 protected $email; 6 7 public function __construct() { 8 // I only know one cat 9 $this->username = "orbit"; 10 $this->email = "[email protected]"; 11 }
  25. Using Another Object Let’s instantiate and use some objects //

    featured users $featured = array( new \User\User("emmajanehw"), new \Animal\Cat()); <h2>Other Excellent Users Of This Site:</h2> <?php foreach($featured as $user): ?> <?=$user->getGravatar()?>&nbsp; <?php endforeach; ?>
  26. Object Identity How can we check if an object has

    a getGravatar() method? Check the object type with instanceof • but one is a Cat and one is a User, and what if we add more types?
  27. Interfaces An interface is a contract. It defines what an

    object can do. We could make a Picturesque interface interface Picturesque { public function getGravatar(); } Good news: autoloading works for interfaces!
  28. Interfaces A Class an implement an interface. Class Cat implements

    Picturesque If it does, it MUST have all the methods defined exactly as in the interface. (ours already do)
  29. Object Identity How can we check if an object has

    a getGravatar() method? Check the object type with instanceof • but one is a Cat and one is a User, and what if we add more types?
  30. Object Identity How can we check if an object has

    a getGravatar() method? Check the object type with instanceof • but one is a Cat and one is a User, and what if we add more types? Only accept objects which implement the Picturesque interface
  31. TypeHinting How to require that a particular interface is used

    function addFeaturedUser(Picturesque $user) { return $user; } Adapt our code to use this function // featured users $featured[] = addFeaturedUser(new \User\User("emmajanehw")); $featured[] = addFeaturedUser(new \Animal\Cat());
  32. Exceptions in PHP Exceptions are Objects; they can be extended

    PHP itself throws exceptions: $db = new PDO("foo", "bar"); PHP Fatal error: Uncaught exception ‘PDOExceptio with message ‘invalid data source name’
  33. Exceptions in PHP We should catch exceptions: 1 try {

    2 // success case code goes here 3 $db = new PDO("foo", "bar"); 4 } catch(PDOException $e) { 5 echo "some DB fail occurred"; 6 }
  34. Throwing Exceptions function addTwoNumbers($a, $b) { if(($a == 0) ||

    ($b == 0)) { throw new Exception("Zero is Boring!"); } return $a + $b; } echo addTwoNumbers(3,2); // 5 echo addTwoNumbers(5,0); // error!! Fatal error: Uncaught exception 'Exception' with message 'Zero is Boring!'
  35. Extending Exceptions We can extend the Exception class for our

    own use 1 class DontBeDaftException extends Exception { 2 } 3 4 function inspectCurtains($colour) { 5 if($colour == "orange" || $colour == "spotty") { 6 throw new DontBeDaftException($colour . 'is daft'); 7 } 8 echo "The curtains are $colour\n"; 9 }
  36. Traits A trait looks a lot like a class, or

    a bit of one 1 trait Gravatar { 2 public function getGravatar() { 3 $url = "http://www.gravatar.com/avatar/" 4 . md5($this->email); 5 return "<img src=\"$url\">"; 6 } 7 } Good news: autoloading works for traits!
  37. Traits Put a trait into your class with the use

    keyword: 1 namespace User; 2 3 class User implements \Picturesque { 4 protected $username; 5 protected $email; 6 7 use \Gravatar; 8 9 public function __construct($username) { 10 ....
  38. Project Overview . ├── inc │ ├── Animal │ │

    └── Cat.php │ ├── Gravatar.php │ ├── Picturesque.php │ └── User │ ├── Admin.php │ └── User.php ├── public │ └── index.php ├── README.md └── templates └── ...
  39. TL;DR • class recipe for making an object • object

    an item with properties and methods • inheritance use one class as basis for another • interface contract agreeement for classes • typehinting how to identify a class • trait how to use the same functionality in two unrelated classes