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

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

More Decks by Josh Butts

Other Decks in Programming

Transcript

  1. PHP Anti Patterns (and how you’re guilty of using them)

    Josh Butts PHP Benelux 2015
  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
  3. None
  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
  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)
  6. What is an Anti-Pattern

  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?
  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
  9. NIH Syndrome • Everyone should write their own X •

    Don’t actually use it • Re-inventing an already documented bad idea
  10. Singletons You might as well just use global variables

  11. Examples • Public statics • Service locators • Bad DI

    Containers
  12. Why would you use a singleton • Cross-cutting concerns •

    Configuration options • State-passing in a legacy system
  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; } }
  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
  15. Your First PHP Job

  16. Your Second PHP Job

  17. Database IPC Your database is not a job queue

  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…
  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
  20. But I would never database IPC! I bet you would.

  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
  22. Interface Bloat In reality, no one will build an alternate

    implementation
  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?
  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
  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); }
  26. None
  27. Enough with OOP Lets talk about about plain old PHP

  28. Mixed returns • Check your data models • Check your

    database • E_FATAL
  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; } }
  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(); } }
  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(); } }
  32. Extract Not even once…

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

    index.php?page=1 $importantVariable = 1; extract($_GET); //$page == 1;
  34. Error Handling Throw a damn exception!

  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
  36. Sequential Coupling Your objects require their methods to be called

    in a certain order
  37. Sequential Coupling • Requires setters after constructors • Failure to

    inject dependencies • Requiring external state management • valid() to check state? • Poorly written API clients
  38. Don’t abuse PHP’s goofy booleans You’ll be sorry way down

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

    "Product is rated: " . $rating; } else { //this one executes echo "Product has received no ratings"; }
  40. Rating Example <?php $rating = "0.00"; if ($rating) { //this

    one executes echo "Product is rated: " . $rating; } else { echo "Product has received no ratings"; }
  41. Include abuse You’ll thank me later

  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>
  43. static_homepage.html <h1>Welcome to my blog</h1>

  44. Trouble <h1>Welcome to my blog</h1> <?$date = 'never'?>

  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>
  46. Quick Hits One bullet says it all

  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
  48. The Elusive While-Break I’ve only ever seen this once, so

    maybe it’s not a pattern…
  49. None
  50. <?php $shouldRun = true while ($shouldRun) { $obj->method1(); $obj->method2(); break;

    }
  51. None
  52. What I didn’t mention, on purpose • Not writing tests

    • Not using a framework • Using goto • Mixing PHP and HTML
  53. Questions / Discussion?

  54. Feedback • https://joind.in/13116 • josh@joshbutts.com • @jimbojsb