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

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