PHP Anti-Patterns (PHP Benelux 2015)

44a352b02a91a9e841da7533bc5d9b8e?s=47 Josh Butts
January 23, 2015

PHP Anti-Patterns (PHP Benelux 2015)

44a352b02a91a9e841da7533bc5d9b8e?s=128

Josh Butts

January 23, 2015
Tweet

Transcript

  1. 2.

    About Me • Over 10 years of “pro” PHP •

    VP of Engineering at Offers.com • Austin PHP organizer • Taught several PHP classes • github.com/jimbojsb @jimbojsb
  2. 3.
  3. 4.

    Preface • This talk is 100% my opinion • You

    may disagree with some of it • I disagree with some of it • Find me after and tell me why I’m wrong • PHP is ever-changing. This talk could be wrong 6 months from now
  4. 5.

    What is an Anti-Pattern? An anti-pattern (or antipattern) is a

    common response to a recurring problem that is usually ineffective and risks being highly counterproductive. (so says Wikipedia)
  5. 7.

    What is an Anti-Pattern • Tend to appear in OOP

    • Contradict good OOP patterns • In PHP, there are plenty of non-oop examples too • Why does the PHP let us do it then?
  6. 8.

    Everyone Is Guilty • Road to hell is paved with

    good intentions • Lesser of the evils • Good software design doesn’t (necessarily) make money • Blame PHP
  7. 9.

    NIH Syndrome • Everyone should write their own X •

    Don’t actually use it • Re-inventing an already documented bad idea
  8. 12.

    Why would you use a singleton • Cross-cutting concerns •

    Configuration options • State-passing in a legacy system
  9. 13.

    Example Singleton Class <?php class Singleton { private static $instance;

    public static function getInstance() { if (!($instance instanceof self)) { self::$instance = new self(); } return self::$instance; } }
  10. 14.

    God Objects - The Worst Singletons Zend_Controller_Front • The core

    request handler for Zend Framework 1.x • Singleton with a public getInstance() method • Has a reference to EVERYTHING • Change the response code from your view • Disable exception handling from your models • Really, very, extremely convenient
  11. 18.

    Database IPC • We’ve all done this • Probably at

    your second PHP job • MySQL is your everything • But it’s easy and it works…
  12. 19.

    Database IPC • Sure, it works on your local dev

    laptop • I promise this will fail you in production • Why: Locking, polling, IO, query cache • MediaWiki
  13. 21.

    How do you fix it? • Use a message or

    job queue • There are a ton of good ones • Beanstalkd • RabbitMQ • Gearman • Kafka • Amazon SQS
  14. 23.

    Interface Bloat - How it starts out • Step 1

    - Write Code • Step 2 - Publish on Github • Step 3 - Tweet your new lib • Step 4 - Fame?
  15. 24.

    Interface Bloat • Why do you use interfaces • Who

    is the audience of your code • Is there a reason to extend what you wrote? • Slippery slope • Java Envy
  16. 25.

    Pheanstalk\Pheanstalk <?php namespace Pheanstalk; interface PheanstalkInterface { const DEFAULT_PORT =

    11300; const DEFAULT_DELAY = 0; // no delay const DEFAULT_PRIORITY = 1024; // most urgent: 0, least urgent: 4294967295 const DEFAULT_TTR = 60; // 1 minute const DEFAULT_TUBE = 'default'; public function setConnection(Connection $connection); public function getConnection(); public function bury($job, $priority = self::DEFAULT_PRIORITY); public function delete($job); public function ignore($tube); public function kick($max); public function kickJob($job); public function listTubes(); public function listTubesWatched($askServer = false); public function listTubeUsed($askServer = false); public function pauseTube($tube, $delay); public function peek($jobId); public function peekReady($tube = null); public function peekDelayed($tube = null); public function peekBuried($tube = null); public function put($data, $priority = self::DEFAULT_PRIORITY, $delay = self::DEFAULT_DELAY, $ttr = self::DEFAULT_TTR); public function putInTube($tube, $data, $priority = self::DEFAULT_PRIORITY, $delay = self::DEFAULT_DELAY, $ttr = self::DEFAULT_TTR); public function release($job, $priority = self::DEFAULT_PRIORITY, $delay = self::DEFAULT_DELAY); public function reserve($timeout = null); public function reserveFromTube($tube, $timeout = null); public function statsJob($job); public function statsTube($tube); public function stats(); public function touch($job); public function useTube($tube); public function watch($tube); public function watchOnly($tube); }
  17. 26.
  18. 29.

    Common DB Example <?php class DB { public function query($sql)

    { $results = mysql_query($sql); if ($results) { $data = array(); while ($row = mysql_fetch_assoc($results)) { $data[] = $row; } return $data; } return false; } }
  19. 30.

    Slightly better - return array() <?php class DB { public

    function query($sql) { $results = mysql_query($sql); if ($results) { $data = array(); while ($row = mysql_fetch_assoc($results)) { $data[] = $row; } return $data; } return array(); } }
  20. 31.

    Better still <?php class DB { public function query($sql) {

    $results = mysql_query($sql); if ($err = mysql_error()) { throw new \RuntimeException($err); } if ($results) { $data = array(); while ($row = mysql_fetch_assoc($results)) { $data[] = $row; } return $data; } return array(); } }
  21. 33.

    This is just a bad idea all around <?php //

    index.php?page=1 $importantVariable = 1; extract($_GET); //$page == 1;
  22. 35.

    trigger_error() • From hard to impossible to handle during runtime

    • Just use exceptions - we even have finally now • Still 17 occurrences of trigger_error() in the Wordpress codebase • 22 in Joomla • Surprisingly only 3 in Drupal 8, and the seem to be outside the core
  23. 37.

    Sequential Coupling • Requires setters after constructors • Failure to

    inject dependencies • Requiring external state management • valid() to check state? • Poorly written API clients
  24. 39.

    Rating Example <?php $rating = “0"; if ($rating) { echo

    "Product is rated: " . $rating; } else { //this one executes echo "Product has received no ratings"; }
  25. 40.

    Rating Example <?php $rating = "0.00"; if ($rating) { //this

    one executes echo "Product is rated: " . $rating; } else { echo "Product has received no ratings"; }
  26. 42.

    Include means parse and eval <?php $date = date("Y-m-d"); ?>

    <html> <head> <title>My Blog</title> </head> <body> <?include "static_homepage.html"?> </body> <footer> Last updated: <?=$date?> </footer> <html>
  27. 45.

    Include means parse and eval <?php $date = date("Y-m-d"); ?>

    <html> <head> <title>My Blog</title> </head> <body> <?include "static_homepage.html"?> </body> <footer> Last updated: <?=$date?> </footer> <html>
  28. 47.

    Quick Hits • Writing your own password hashing • Having

    more than one require call in your code • $_SESSION is not for global storage • Changing the memory_limit • Running PHP <5.5 • Making assumptions about “goodness” of built in language functions • @ • E_ALL
  29. 49.
  30. 51.
  31. 52.

    What I didn’t mention, on purpose • Not writing tests

    • Not using a framework • Using goto • Mixing PHP and HTML