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

PHP Anti-Patterns (PHP World 2014)

Josh Butts
November 14, 2014

PHP Anti-Patterns (PHP World 2014)

Most programming conferences these days have a talk on object-oriented design patterns. Everyone is happy to tell you how you SHOULD be writing code. In this talk we will cover how NOT to write PHP. I've scoured the internet for examples of common pitfalls for PHP developers from beginner to advanced. We'll take a lighthearted yet serious look at issues like security, performance, code style, quirks of the language, and more.

Josh Butts

November 14, 2014
Tweet

More Decks by Josh Butts

Other Decks in Programming

Transcript

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

    VP of Engineering at Offers.com • Long-time Austin PHP organizer • Taught several PHP classes • I play competitive Skee Ball • github.com/jimbojsb @jimbojsb
  2. 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
  3. 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)
  4. What is an Anti-Pattern • Tend to appear in OOP

    • Contradict good OOP patterns • In PHP, there are plenty of non-ooo examples too • Why does the PHP let us do it then?
  5. 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
  6. NIH Syndrome • Everyone should write their own X •

    Don’t actually use it • Re-inventing an already documented bad idea
  7. Why would you use a singleton • Cross-cutting concerns •

    Configuration options • State-passing in a legacy system
  8. Example Singleton Class <?php class Singleton { private static $instance;

    public static function getInstance() { if (!($instance instanceof self)) { self::$instance = new self(); } return self::$instance; } }
  9. 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
  10. Database IPC • We’ve all done this • Probably at

    your second PHP job • MySQL is your everything • But it’s easy and it works…
  11. 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
  12. How do you fix it? • Use a message or

    job queue • There are a ton of good ones • Beanstalkd • RabbitMQ • Gearman • Kafka • Amazon SQS
  13. Interface Bloat - How it starts out • Step 1

    - Write Code • Step 2 - Publish on Github • Step 3 - Tweet your new lib • Step 4 - Fame?
  14. 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
  15. 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); }
  16. 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; } }
  17. 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(); } }
  18. 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(); } }
  19. This is just a bad idea all around <?php //

    index.php?page=1 $importantVariable = 1; extract($_GET); //$page == 1;
  20. 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
  21. Sequential Coupling • Requires setters after constructors • Failure to

    inject dependencies • Requiring external state management • valid() to check state? • Poorly written API clients
  22. Rating Example <?php $rating = “0"; if ($rating) { echo

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

    one executes echo "Product is rated: " . $rating; } else { echo "Product has received no ratings"; }
  24. Quick Hits • Writing your own password hashing • Having

    more than one require call in your code • Writing your own ORM • Changing the memory_limit • Running PHP <5.5 • Making assumptions about “goodness” of built in language functions • @ • ?>
  25. What I didn’t mention, on purpose • Not writing tests

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