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

Defensive programming

Defensive programming

Tips & tricks how anybody can defend own PHP code against misuse by others - PHPUG Dresden 5th Meetup 2017

Tommy Mühle

May 24, 2017
Tweet

More Decks by Tommy Mühle

Other Decks in Programming

Transcript

  1. Tommy Mühle | tommy-muehle.io 9 class Counter { private $count

    = 0; public function add(int $count) { $this->count += $count; } }
  2. Tommy Mühle | tommy-muehle.io 11 class Customer { private $isVerified

    = false; public function verify() : void { $this->isVerified = true; } public function isVerified() : bool { return $this->isVerified; } }
  3. Tommy Mühle | tommy-muehle.io 16 class Counter { public function

    add($count) { $this->ensureIsInteger($count); // ... } private function ensureIsInteger($value) { // ... throw new \RuntimeException('...'); } }
  4. Tommy Mühle | tommy-muehle.io 18 use Assert\Assertion; class Counter {

    private $count; /** * @param int $count */ public function add($count) { Assertion::integer($count); $this->count += $count; } }
  5. Tommy Mühle | tommy-muehle.io 21 class Person { private $address;

    /** * @param Address $address */ public function __construct(Address $address) { $this->address = $address; } }
  6. Tommy Mühle | tommy-muehle.io 23 class Person { // ...

    /** * @param Address $address */ public function __construct(Address $address){ ... } public static function createDetailedPerson( Address $address, Details $details) { $person = new self($address); $person->details = $details; return $person; } }
  7. Tommy Mühle | tommy-muehle.io 29 Avoid primitive types class Person

    { // ... public function addEmail(string $email) { // ... } public function addAddress(array $address) { // ... } }
  8. Tommy Mühle | tommy-muehle.io 30 class Person { // ...

    public function addEmail(EmailAddress $email) { // ... } public function addAddress(Address $address) { // ... } } Use value objects
  9. Tommy Mühle | tommy-muehle.io 31 final class Email { private

    $mailbox; private $host; public function __construct(string $email) { if (false === strpos($email, '@')) { throw new \InvalidArgumentException( 'This does not look like an email!'); } list($this->mailbox, $this->host) = explode('@', $email); } public function __toString() { return sprintf('%s@%s', $this->mailbox, $this->host); } }
  10. Tommy Mühle | tommy-muehle.io 33 abstract class User { //

    ... } final class GuestUser extends User { // ... }
  11. Tommy Mühle | tommy-muehle.io 33 abstract class User { //

    ... } final class GuestUser extends User { // ... }
  12. Tommy Mühle | tommy-muehle.io 38 trait EventGenerator { private $events;

    public function releaseEvents() { $pendingEvents = $this->events; $this->events = []; return $pendingEvents; } protected function raiseEvent(DomainEvent $event) { $this->events[] = $event; } }
  13. class Person { private $birthday; /** * @return null|int */

    public function getAge() { if (!isset($this->birthday)) { return null; } // Calculate $age ... return $age; } } Tommy Mühle | tommy-muehle.io 41
  14. Tommy Mühle | tommy-muehle.io 42 class Person { private $birthday;

    /** * @return int * @throws InvalidArgumentException */ public function getAge() { if (!isset($this->birthday)) { throw new InvalidArgumentException('...'); } // Calculate and return $age ... } public function hasBirthday() { return isset($this->birthday); } }
  15. Tommy Mühle | tommy-muehle.io 45 final class Order { /**

    @var Money */ private $price; /** @var Discount */ private $discount; public function getPrice() { $priceWithDiscount = $this->price; if (!$this->discount instanceof Discount) { return $priceWithDiscount; } // ... return new Money($priceWithDiscount); } }
  16. Tommy Mühle | tommy-muehle.io 47 interface Amountable { public function

    getAmount(); } final class HeavyUserDiscount implements Amountable { public function getAmount() { $amount = 0.00; // ... return new Money($amount); } }
  17. Tommy Mühle | tommy-muehle.io 48 interface Amountable { public function

    getAmount(); } final class NoDiscount implements Amountable { public function getAmount() { return new Money(0.00); } }
  18. Tommy Mühle | tommy-muehle.io 49 final class Order { /**

    @var Money */ private $price; /** @var Discount */ private $discount; public function getPrice() { $amount = $this->price->getAmount() - $this->discount->getAmount(); return new Money($amount); } }
  19. class Person { private $address; private $details; public function __construct(

    Address $address, Details $details = null) { $this->address = $address; $this->details = $details; } } Tommy Mühle | tommy-muehle.io 51
  20. Tommy Mühle | tommy-muehle.io 52 class Person { private $address;

    private $details; // ... public function __construct(Address $address) { $this->address = $address; } public function addDetails(Details $details) { $this->details = $details; } }
  21. Tommy Mühle | tommy-muehle.io 54 class Person { // ...

    public function __clone() { throw new LogicException( 'Why would you even clone me?'); } public function __sleep() { throw new BadMethodCallException( 'Serialize, really?'); } }