Slide 1

Slide 1 text

defensive(programming

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

use$a$framework

Slide 4

Slide 4 text

don't&trust&users (meet%bobby%tables)

Slide 5

Slide 5 text

secure&input

Slide 6

Slide 6 text

filter_var( $input, FILTER_VALIDATE_BOOLEAN ); FILTER_VALIDATE_EMAIL; FILTER_VALIDATE_IP; FILTER_VALIDATE_REGEXP; FILTER_VALIDATE_URL; # php.net/function.filter_var

Slide 7

Slide 7 text

v::alnum() ->length(1, 15) ->validate("PHP 6"); v::regex("/[a-z]/")->validate("a"); v::startsWith("lorem")->validate("lorem ipsum"); v::leapYear()->validate("1988"); v::macAddress()->validate("af-AA-22-33-44-55"); # github.com/respect/validation

Slide 8

Slide 8 text

use$db$abstrac+ons

Slide 9

Slide 9 text

/** * @entity * @table(name="cakes") */ class Cake { /** * @var string * @column(type="string") */ protected $type; /** * @param string $type */ public function setType($type) { $this->type = $type; } }

Slide 10

Slide 10 text

$config = Setup::createAnnotationMetadataConfiguration( ["src"], $isDevMode = true ); $cake = new Cake(); $cake->setType("Brownie"); $manager = EntityManager::create($connection, $config); $manager->persist($cake); $manager->flush(); # github.com/doctrine/doctrine2

Slide 11

Slide 11 text

$query = $factory->newSelect(); $query ->cols(["id", "type"]) ->from("cakes") ->where("cake.type = ?", "brownie"); print $query->getStatement(); # github.com/auraphp/aura.sqlquery

Slide 12

Slide 12 text

just%don't%interpolate%strings%in%queries!

Slide 13

Slide 13 text

rather&use&prepared&statements or#something#equally#secure

Slide 14

Slide 14 text

secure&output

Slide 15

Slide 15 text

$before = "This is an example of
some html content! click for drama console.log('boo!');"; $after = strip_tags($before, "
"); "This is an example of
some html content!" # php.net/function.strip_tags

Slide 16

Slide 16 text

$before = "This is an example of
some html content! click for drama console.log('boo!');"; $after = htmlentities($before); "This is an example of<br> some html content! <a href='http://twitter.com'>click for drama</a> <script>console.log('boo!');</script>" # php.net/function.htmlentities

Slide 17

Slide 17 text

don't&trust&developers (that%includes%you)

Slide 18

Slide 18 text

write&tests

Slide 19

Slide 19 text

seriously,*write*tests

Slide 20

Slide 20 text

i'm$not$kidding

Slide 21

Slide 21 text

cleancoders.com grumpy'learning.com

Slide 22

Slide 22 text

follow%solid%principles

Slide 23

Slide 23 text

hint%types

Slide 24

Slide 24 text

function addTaskToQueue(Task $task, SplQueue $queue) { $clone = clone $queue; $clone->enqueue($task); return $clone; } function fetchProducts(array $products, Closure $then) { $then( array_map(function(Product $product) { return file_get_contents("http://api.com/{$product->id}"); }, $products) ); }

Slide 25

Slide 25 text

function addTaxToPrice(float $percentage, float $price): float { return $price + ($price * $percentage); } declare(strict_types=1); $newPrice = addTaxToPrice(0.14, 120.0); # wiki.php.net/rfc/return_types # wiki.php.net/rfc/scalar_type_hints_v5

Slide 26

Slide 26 text

un#l%then...

Slide 27

Slide 27 text

/** * @param float $percentage * @param float $price * @return float */ function addTaxToPrice($percentage, $price) { assert(is_float($percentage)); assert(is_float($price)); return $price + ($price * $percentage); } # php.net/function.assert

Slide 28

Slide 28 text

use$immutable$types

Slide 29

Slide 29 text

/** * @param float $amount * @param string $reason * @param DateTime $timestamp */ public function __construct($amount, $reason, DateTime $timestamp) { assert(is_float($amount)); assert(is_string($reason)); $this->amount = $amount; $this->reason = $reason; $this->timestamp = $timestamp; }

Slide 30

Slide 30 text

$timestamp = new DateTime("2015-06-26 12:15:00"); $transaction1 = new Transaction( 12.0, "bought a burrito", $timestamp ); $transaction2 = new Transaction( 9.0, "had shoes polished", $timestamp ); $timestamp->setTime(12, 20);

Slide 31

Slide 31 text

/** * @param string $type */ public function withType($type) { assert(is_string($type)); $clone = clone $this; $clone->type = $type; return $clone; }

Slide 32

Slide 32 text

/** * @param string $property * @param mixed $value */ public function cloneWith($property, $value) { $clone = clone $this; $clone->$property = $value; return $clone; } /** * @param string $type */ public function withType($type) { assert(is_string($type)); return $this->cloneWith("type", $type); }

Slide 33

Slide 33 text

clone&is&shallow, so#manage#deep#cloning#yourself

Slide 34

Slide 34 text

write&simple&code (it's&the&hardest&thing)

Slide 35

Slide 35 text

do#the#one#thing

Slide 36

Slide 36 text

function sendOrdersAndRenderInvoice(array $orders, $templatePath) { foreach ($orders as $order) { if (!($order instanceof Order)) { throw new InvalidArgumentException("Invalid order type"); } try { $this->api->send($order); } catch (ApiException $exception) { $this->logger->log("There was a problem sending an order"); throw $exception; } } if (!file_exists($templatePath)) { throw new InvalidArgumentException("Template not found"); } $template = file_get_contents($templatePath); return $this->renderer->render($template, $orders); }

Slide 37

Slide 37 text

function sendOrders(array $orders) { $this->validateOrders($orders); foreach ($orders as $order) { $this->sendOrder($order); } } function validateOrders(array $orders) { foreach ($orders as $order) { if (!($order instanceof Order)) { throw new InvalidArgumentException("Invalid order type"); } }; } function sendOrder(Order $order) { try { $this->api->send($order); } catch (ApiException $exception) { $this->logger->log("There was a problem sending an order"); throw $exception; } }

Slide 38

Slide 38 text

exit%early

Slide 39

Slide 39 text

function openAccount(AccountHolder $holder, AccountType $type) { if ($holder->getAge() > 18 || $holder->hasParentPermission()) { if (in_array($type->getName(), $holder->getAllowedAccountTypes())) { if ($this->canOpenAccountType($type->getName())) { $this->openApprovedAccount($holder, $type); return true; } } } return false; }

Slide 40

Slide 40 text

function openAccount(AccountHolder $holder, AccountType $type) { if ($holder->getAge() < 18 && !$holder->hasParentPermission()) { return false; } if (!in_array($type->getName(), $holder->getAllowedAccountTypes())) { return false; } if ($this->canOpenAccountType($type->getName())) { return false; } $this->openApprovedAccount($holder, $type); return true; }

Slide 41

Slide 41 text

avoid&flag¶meters

Slide 42

Slide 42 text

$template = $this->getTemplate($templatePath, false); $template = trim($template); return $this->renderer->render($template, $data, false);

Slide 43

Slide 43 text

avoid&mixed¶meter/return&types

Slide 44

Slide 44 text

use$value$objects

Slide 45

Slide 45 text

thanks joind.in/14209 twi$er.com/assertchris