Good Morning!
I'm Chad

AKA Chadicus

I like PHP
I also like the Hulk
I helped create DE DevCon

Defensive Coding for Dummies

What is Defensive Coding?
Similar to Defensive Drving
Drive assuming everyone around you can make a mistake.
Write code assuming anyone who uses it can and will make a mistake.
Your job is to limit the mistakes they can make
Users of your code should have one clear path to perform any task.
Code for your use case, not your re-use case
DISCLAIMER
Stop using setters
```php class Notifier { public function __construct(...) { // ... } public function setMailer(MailerInterface $mailer) { $this->mailer = $mailer; } } ```
Setters are useless
Inject dependencies in constructor
```php class Notifier { public function __construct(MailerInterface $mailer) { $this->mailer = $mailer; } } ```
```php class Notifier { public function __construct(MailerInterface $mailer) { $this->mailer = $mailer; } } $notifier = new Notifier(new FakeMailer()); ``` Note: * Tell, don't ask * If the null/fake implementation of your dependency doesn't exist. Create it. * Single responsibility
Inject ALL Dependencies
```php class Notifier { public function __construct(MailerInterface $mailer) { $this->database = DbConnection::getInstance(); $this->mailer = $mailer; } } ```
```php class Notifier { public function __construct( MailerInterface $mailer, DbConnection $database ) { $this->database = $database; $this->mailer = $mailer; } } ``` Note: * Static access causes unexchangeable dependencies to other classes and leads to hard to test code * Use of the new keyword in a constructor should be a code smell
Avoid Unnecessary Public Methods
```php class Listing { const REALM_ID = 4; // ... public function getRealmId() { return self::REALM_ID; } } ``` Note: A public method is like a child

"A public method is like a child: once you've written it, you are going to maintain it for the rest of its life!"
- Stefan Priebsch

Avoid Logic Switch Parameters
```php public function getPhotoUrl($useCdn = false) { // ... } ``` Note: * Violates Single Responsibility Principle
```php public function getPhotoUrl() { // ... } public function getCdnPhotoUrl() { // ... } ``` Note: * Worth the extra effort
All State Should be Encapsulated
```php class Ad { private $created; public function __construct(\DateTime $dateTime) { $this->created = $dateTime; } // ... } ``` ```php $now = new \DateTime(); $ad = new Ad($now); ``` ``` // Do stuff ... ``` ```php $now->setTimestamp($aTimestamp); ``` Note: * State of ad can be changed without its knowledge
```php public function __construct(\DateTime $dateTime) { $this->created = clone $dateTime; } ``` ```php public function __construct(\DateTimeImmutable $dateTime) { $this->created = $dateTime; } ``` Note: * clone the dependency * or use immutable implementation
Private Properties Only
No Mixed Parameter Types
```php /** * Gets the options of the object. * * @param mixed $options Array, config object or a json string. * * @return void */ public function setOptions($options = null) { // ... } ``` Note: * Simplified example. Do not use a setter * Pick a type, make the calling code perform the conversion
No Mixed Return Types
Make Classes FINAL by Default
Disable Cloning and Serialization by Default
```php public function __clone() { throw new \BadMethodCallException( 'Cloning of this object is not allowed' ); } ``` Note: * Do you need to clone or serialize? * Is it part of your use case? * Do you know the lifecycle of every dependency * Cloning requires encapsulated state understanding * If cloning is part of your use case, ensure deep cloning
Test ALL Scenarios
```php /** * Authenticate the user. * * @param string $username * @param string $password * * @return bool * * @throws InvalidArgumentException * @throws AuthenticateException * @throws DomainException */ public function authenticate($username, $password); ``` Note: * A lot can happen with this method * A TRUE is returned * A FALSE is returned * InvalidArgumentException is thrown * AuthenticateException is thrown * DomainException is thrown * 5 tests

Recap

Inject ALL dependencies with constructor

Avoid Unnecessary Public Methods

Avoid Logic Switch Parameters

All State Should be Encapsulated

No Mixed Parameter or Return Types

Make Classes FINAL by Default

Disable Cloning and Serialization by Default

Test ALL Scenarios

Questions?
Fill out the Survey
http://devcon.dominionenterprises.com/2016/survey