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

PHP Anti-Patterns (PHP Benelux 2015)

Josh Butts
January 23, 2015

PHP Anti-Patterns (PHP Benelux 2015)

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

    View full-size slide

  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

    View full-size slide

  3. 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

    View full-size slide

  4. 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)

    View full-size slide

  5. What is an Anti-Pattern

    View full-size slide

  6. 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?

    View full-size slide

  7. 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

    View full-size slide

  8. NIH Syndrome
    • Everyone should write their own X
    • Don’t actually use it
    • Re-inventing an already documented bad
    idea

    View full-size slide

  9. Singletons
    You might as well just use global variables

    View full-size slide

  10. Examples
    • Public statics
    • Service locators
    • Bad DI Containers

    View full-size slide

  11. Why would you use a singleton
    • Cross-cutting concerns
    • Configuration options
    • State-passing in a legacy system

    View full-size slide

  12. Example Singleton Class
    class Singleton
    {
    private static $instance;
    public static function getInstance()
    {
    if (!($instance instanceof self)) {
    self::$instance = new self();
    }
    return self::$instance;
    }
    }

    View full-size slide

  13. 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

    View full-size slide

  14. Your First PHP Job

    View full-size slide

  15. Your Second PHP Job

    View full-size slide

  16. Database IPC
    Your database is not a job queue

    View full-size slide

  17. Database IPC
    • We’ve all done this
    • Probably at your second PHP job
    • MySQL is your everything
    • But it’s easy and it works…

    View full-size slide

  18. 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

    View full-size slide

  19. But I would never database IPC!
    I bet you would.

    View full-size slide

  20. How do you fix it?
    • Use a message or job queue
    • There are a ton of good ones
    • Beanstalkd
    • RabbitMQ
    • Gearman
    • Kafka
    • Amazon SQS

    View full-size slide

  21. Interface Bloat
    In reality, no one will build an alternate implementation

    View full-size slide

  22. Interface Bloat - How it starts out
    • Step 1 - Write Code
    • Step 2 - Publish on Github
    • Step 3 - Tweet your new lib
    • Step 4 - Fame?

    View full-size slide

  23. 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

    View full-size slide

  24. Pheanstalk\Pheanstalk
    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);
    }

    View full-size slide

  25. Enough with OOP
    Lets talk about about plain old PHP

    View full-size slide

  26. Mixed returns
    • Check your data models
    • Check your database
    • E_FATAL

    View full-size slide

  27. Common DB Example
    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;
    }
    }

    View full-size slide

  28. Slightly better - return array()
    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();
    }
    }

    View full-size slide

  29. Better still
    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();
    }
    }

    View full-size slide

  30. Extract
    Not even once…

    View full-size slide

  31. This is just a bad idea all around
    // index.php?page=1
    $importantVariable = 1;
    extract($_GET);
    //$page == 1;

    View full-size slide

  32. Error Handling
    Throw a damn exception!

    View full-size slide

  33. 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

    View full-size slide

  34. Sequential Coupling
    Your objects require their methods to be called in a certain order

    View full-size slide

  35. Sequential Coupling
    • Requires setters after constructors
    • Failure to inject dependencies
    • Requiring external state management
    • valid() to check state?
    • Poorly written API clients

    View full-size slide

  36. Don’t abuse PHP’s goofy booleans
    You’ll be sorry way down the road

    View full-size slide

  37. Rating Example
    $rating = “0";
    if ($rating) {
    echo "Product is rated: " . $rating;
    } else {
    //this one executes
    echo "Product has received no ratings";
    }

    View full-size slide

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

    View full-size slide

  39. Include abuse
    You’ll thank me later

    View full-size slide

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


    My Blog





    Last updated: =$date?>


    View full-size slide

  41. static_homepage.html
    Welcome to my blog

    View full-size slide

  42. Trouble
    Welcome to my blog
    $date = 'never'?>

    View full-size slide

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


    My Blog





    Last updated: =$date?>


    View full-size slide

  44. Quick Hits
    One bullet says it all

    View full-size slide

  45. 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

    View full-size slide

  46. The Elusive While-Break
    I’ve only ever seen this once, so maybe it’s not a pattern…

    View full-size slide

  47. $shouldRun = true
    while ($shouldRun) {
    $obj->method1();
    $obj->method2();
    break;
    }

    View full-size slide

  48. What I didn’t mention, on purpose
    • Not writing tests
    • Not using a framework
    • Using goto
    • Mixing PHP and HTML

    View full-size slide

  49. Questions / Discussion?

    View full-size slide

  50. Feedback
    • https://joind.in/13116
    [email protected]
    • @jimbojsb

    View full-size slide