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

Why Modern PHP is Awesome And How You Can Use It Today

Why Modern PHP is Awesome And How You Can Use It Today

From PeersConf 2014, a conference primarily for PHP developers working with ExpressionEngine, Craft, Statamic, and CodeIgniter.

The PHP language and its community have seen incredible growth in the last few years. It can be hard to keep up with the pace of new development, and harder to keep our sites up-to-date. But these new packages, practices, and SAASes have amazing potential to improve our sites' flexibility, power, ease of development, and longevity. This isn't just for brand-new frameworks like Laravel, either--CMSes like Craft and PyroCMS have them baked in, and even ExpressionEngine and Codeigniter can be modified to work with modern PHP. Learn about Composer, Packagist, SOLID, SAASes, exceptions, PSRs, and how these and many more tools and practices will transform your experience of PHP.

Matt Stauffer

April 25, 2014
Tweet

More Decks by Matt Stauffer

Other Decks in Programming

Transcript

  1. Modern PHP
    is Amazing
    You Can Use It
    Today
    @stauffermatt
    A N D
    Why
    How

    View Slide

  2. Matt Stauffer
    @stauffermatt

    View Slide

  3. Gainesville

    View Slide

  4. My history
    Graphic
    Design

    View Slide

  5. My history
    Graphic
    Design Frontend

    View Slide

  6. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress

    View Slide

  7. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress
    Left for 5 years

    View Slide

  8. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress CodeIgniter
    Left for 5 years

    View Slide

  9. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress CodeIgniter
    Expression
    Engine
    Left for 5 years

    View Slide

  10. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress CodeIgniter
    Expression
    Engine Rails
    Left for 5 years

    View Slide

  11. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress CodeIgniter
    Expression
    Engine Rails Laravel
    Left for 5 years

    View Slide

  12. My history
    Graphic
    Design Frontend
    Hacky PHP
    & Wordpress CodeIgniter
    Expression
    Engine Rails Laravel
    General
    Good
    Developer-y
    Stuff
    Left for 5 years

    View Slide

  13. Who are we?

    View Slide

  14. Who are we?
    Self-taught

    View Slide

  15. Who are we?
    Self-taught
    Wordpress, EE, CI, etc.

    View Slide

  16. Who are we?
    Self-taught
    Wordpress, EE, CI, etc.
    Bootstrappy small-to-medium companies

    View Slide

  17. Who are we?
    Self-taught
    Wordpress, EE, CI, etc.
    Bootstrappy small-to-medium companies
    “Lone cowboy” types*

    View Slide

  18. Our tools are
    holding us back.
    THE PROBLEM:

    View Slide

  19. Our tools are
    holding us back.
    THE PROBLEM:
    (certain of)

    View Slide

  20. Our tools are
    holding us back.
    THE PROBLEM:
    (certain of)
    THE SOLUTION:

    View Slide

  21. Our tools are
    holding us back.
    THE PROBLEM:
    (certain of)
    Fix (or ditch) them.
    THE SOLUTION:

    View Slide

  22. Disclaimers:

    View Slide

  23. Disclaimers:
    1. You might already know this

    View Slide

  24. Disclaimers:
    1. You might already know this
    2. This may be totally overwhelming

    View Slide

  25. Disclaimers:
    1. You might already know this
    2. This may be totally overwhelming
    3. Easiest in modern environments

    View Slide

  26. Disclaimers:
    1. You might already know this
    2. This may be totally overwhelming
    3. Easiest in modern environments
    4. One size fits some

    View Slide

  27. 5 LESSONS TO MAKE YOUR PHP BETTER

    View Slide

  28. Embrace the Object
    Object Oriented PHP
    LESSON 1

    View Slide

  29. Classic PHP is
    { procedural }

    View Slide

  30. require_once("common.inc");
    $page_slug = getPageSlug($_GET);
    $page_title = getPageTitle($page_slug);
    !
    include_once("templates/header.inc");
    !
    echo getHeaderNav($page_slug);
    !
    // ...
    Procedural PHP

    View Slide

  31. require_once("common.inc");
    $page_slug = getPageSlug($_GET);
    $page_title = getPageTitle($page_slug);
    !
    include_once("templates/header.inc");
    !
    echo getHeaderNav($page_slug);
    !
    // ...
    about.php
    include_once(
    "templates/about.inc"
    );
    !
    include_once(
    "templates/footer.inc"
    );
    Procedural PHP

    View Slide

  32. require_once("common.inc");
    $page_slug = getPageSlug($_GET);
    $page_title = getPageTitle($page_slug);
    !
    include_once("templates/header.inc");
    !
    echo getHeaderNav($page_slug);
    !
    // ...
    about.php
    include_once(
    "templates/about.inc"
    );
    !
    include_once(
    "templates/footer.inc"
    );
    portfolio.php
    $portfolio_items = array(
    array(
    'title' =>
    'Chuck E Cheese',
    'screenshot' =>
    'images/portfolio/
    chuck01.jpg'
    Procedural PHP

    View Slide

  33. require_once("common.inc");
    $page_slug = getPageSlug($_GET);
    $page_title = getPageTitle($page_slug);
    !
    include_once("templates/header.inc");
    !
    echo getHeaderNav($page_slug);
    !
    // ...
    about.php
    include_once(
    "templates/about.inc"
    );
    !
    include_once(
    "templates/footer.inc"
    );
    portfolio.php
    $portfolio_items = array(
    array(
    'title' =>
    'Chuck E Cheese',
    'screenshot' =>
    'images/portfolio/
    chuck01.jpg'
    contact-us.ph
    if(isset($_POST))
    $results = va
    if ($results
    include_o
    } else {
    $errors =
    }
    Procedural PHP

    View Slide

  34. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Object-Oriented PHP

    View Slide

  35. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Name Object-Oriented PHP

    View Slide

  36. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Name
    Properties
    Object-Oriented PHP

    View Slide

  37. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Name
    Properties
    Constructor
    Object-Oriented PHP

    View Slide

  38. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Name
    Properties
    Constructor
    Public method
    Object-Oriented PHP

    View Slide

  39. class Portfolio_item
    {
    public $id;
    public $title;
    public $url;
    protected $cache_images;
    !
    public function __construct(array $properties)
    {
    $this->hydrate($properties);
    }
    !
    public function getRelatedImages()
    {
    if ($this->cache_images === null) {
    $this->cacheRelatedImages();
    }
    !
    return $this->cache_images;
    }
    !
    protected function hydrate(array $properties)
    Name
    Properties
    Constructor
    Public method
    Protected method
    Object-Oriented PHP

    View Slide

  40. !
    !
    !
    !
    !

    !
    = $item->title; ?>
    !
    Images
    !

    getRelatedImages() as $image): ?>



    View Slide

  41. PHP is an
    OOP late bloomer
    2007 2015
    2011
    2003
    1999
    1995

    View Slide

  42. PHP is an
    OOP late bloomer
    2007 2015
    2011
    2003
    1999
    1995
    PHP
    released
    1995

    View Slide

  43. PHP is an
    OOP late bloomer
    2007 2015
    2011
    2003
    1999
    1995
    PHP 5.3
    (true OOP)
    PHP
    released
    1995

    View Slide

  44. PHP is an
    OOP late bloomer
    2007 2015
    2011
    2003
    1999
    1995
    PHP 5.3
    (true OOP)
    PHP
    released
    1995
    PHP 5.2
    EOL’ed

    View Slide

  45. PHP is an
    OOP late bloomer
    2007 2015
    2011
    2003
    1999
    1995
    PHP 5.3
    (true OOP)
    PHP
    released
    1995
    5.3 50%
    adoption
    PHP 5.2
    EOL’ed

    View Slide

  46. CodeIgniter
    taught me OOP

    View Slide

  47. CodeIgniter
    taught me OOP
    some OOP-y things

    View Slide

  48. 1) Separation of Concerns
    (MVC)

    View Slide

  49. 2) Single Responsibility Principle
    3) Modules
    4) Singletons
    (Libraries)

    View Slide

  50. CodeIgniter libraries are
    usually just wrappers around
    a few related functions

    View Slide

  51. CodeIgniter Developer
    != (necessarily)
    OOP Developer

    View Slide

  52. brandon ruined me

    View Slide

  53. What OOP isn’t

    View Slide

  54. What OOP isn’t
    Taking all of your old DB-
    related functions & bundling
    them into a "model"

    View Slide

  55. Taking all of your old
    functions & bundling them
    into a "library"
    What OOP isn’t

    View Slide

  56. echo
    createFullDisplayNameForContactReversed(
    $prefix,
    $first_name,
    $middle_name,
    $last_name,
    $suffix,
    etc.);
    What OOP isn’t

    View Slide

  57. What OOP is

    View Slide

  58. What OOP is
    things
    that do
    things
    to other
    things
    thing
    thing
    thing

    View Slide

  59. Windows:Mac/*nix
    ::
    Procedural:OOP

    View Slide

  60. Foundations Of OOP

    View Slide

  61. Interfaces

    View Slide

  62. SOLID

    View Slide

  63. SOLID
    1. Single Responsibility

    View Slide

  64. SOLID
    1. Single Responsibility
    2. Open-Closed

    View Slide

  65. SOLID
    1. Single Responsibility
    2. Open-Closed
    3. Liskov Substitution

    View Slide

  66. SOLID
    1. Single Responsibility
    2. Open-Closed
    3. Liskov Substitution
    4. Interface Segregation

    View Slide

  67. SOLID
    1. Single Responsibility
    2. Open-Closed
    3. Liskov Substitution
    4. Interface Segregation
    5. Dependency Inversion

    View Slide

  68. thing2
    thing1
    Tight Coupling

    View Slide

  69. thing2
    thang
    thing1
    Tight Coupling

    View Slide

  70. thing2
    thing1
    injected
    Off Limits
    Law of Demeter

    View Slide

  71. Why OOP?

    View Slide

  72. Sharing & Reuse
    Why OOP?

    View Slide

  73. Lower cost of debug
    Why OOP?

    View Slide

  74. Lower cost of
    comprehension
    Why OOP?

    View Slide

  75. Limited interfaces
    Why OOP?

    View Slide

  76. Lower cost of
    change
    Why OOP?

    View Slide

  77. Refactor Time

    View Slide

  78. * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array()
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact[
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_ti
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $co
    $contact_title = $contact['contact_title'];

    View Slide

  79. *
    * @todo Get this out of the helper
    * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array() )
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'];
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact['contact_title']) && !
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_sp_title'])) ||
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_title'] == 'Mr.') {
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $contact['contact_title'])
    $contact_title = $contact['contact_title'];
    Extract refactor

    View Slide

  80. *
    * @todo Get this out of the helper
    * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array() )
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'];
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact['contact_title']) && !
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_sp_title'])) ||
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_title'] == 'Mr.') {
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $contact['contact_title'])
    $contact_title = $contact['contact_title'];
    Extract refactor
    $this->appendMiddleNames();

    View Slide

  81. *
    * @todo Get this out of the helper
    * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array() )
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'];
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact['contact_title']) && !
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_sp_title'])) ||
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_title'] == 'Mr.') {
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $contact['contact_title'])
    $contact_title = $contact['contact_title'];
    Extract refactor
    if ($this->hasSpouse()) {
    $this->appendMiddleNames();

    View Slide

  82. *
    * @todo Get this out of the helper
    * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array() )
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'];
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact['contact_title']) && !
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_sp_title'])) ||
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_title'] == 'Mr.') {
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $contact['contact_title'])
    $contact_title = $contact['contact_title'];
    Extract refactor
    if ($this->hasSpouse()) {
    if ( ! $this->hasTitles()) {
    $this->appendMiddleNames();

    View Slide

  83. *
    * @todo Get this out of the helper
    * @param array $contact Contact
    * @param array $options Options
    * @return string Full name
    */
    function returnContactFullName( array $contact, $options = array() )
    {
    // Tack middle name onto first
    if ($contact['contact_mname'] != '') {
    $contact['contact_fname'] .= ' ' . $contact['contact_mname'];
    }
    if ($contact['contact_sp_mname'] != '') {
    $contact['contact_sp_fname'] .= ' '.$contact['contact_sp_mname'];
    }
    !
    if ( ! empty($contact['contact_sp_fname']) || ( ! empty($contact['contact_title']) && !
    empty($contact['contact_sp_title']))) {
    // Contact has a spouse.
    // Prep title
    $contact_title = $spouse_title = NULL;
    !
    if (
    (empty($contact['contact_title']) && empty($contact['contact_sp_title'])) ||
    in_array('no_title', $options)
    ) {
    // No titles. Go without.
    } elseif (empty($contact['contact_sp_title'])) {
    // Title for contact but not spouse. Only can handle if Mr.
    if ($contact['contact_title'] == 'Mr' || $contact['contact_title'] == 'Mr.') {
    $contact['contact_sp_title'] = str_replace('Mr', 'Mrs', $contact['contact_title'])
    $contact_title = $contact['contact_title'];
    Extract refactor
    if ($this->hasSpouse()) {
    if ( ! $this->hasTitles()) {
    $this->duplicateSpouseTitleIfNeeded();
    $this->appendMiddleNames();

    View Slide

  84. !
    class ContactName
    {
    protected $contact_array;
    protected $contact;
    protected $options;
    !
    public function __construct(array $contact_array, array $options = array())
    {
    $this->contact_array = $contact_array;
    $this->options = $options;
    $this->processContactArray();
    }
    !
    public function output()
    {
    return $this->getFullName();
    }
    !
    protected function getFullName()
    {
    if ($this->hasSpouse()) {
    return $this->getFullNameWithSpouse();
    } else {
    return $this->getFullNameIndividual();
    }
    Extract refactor result
    !
    include_once('ContactName.php');
    !
    $name = new ContactName(
    $array_of_name_stuff_from_sql
    );
    echo $name->output();
    Example use:

    View Slide

  85. Instant Re-use

    View Slide

  86. Lone cowboys
    vs.
    Jetsons

    View Slide

  87. Learn from those who
    came before you
    Design Patterns &
    Coding Standards
    LESSON 2

    View Slide

  88. Design Patterns

    View Slide

  89. The Human
    Brain Identifies
    Patterns
    https://www.flickr.com/photos/flamephoenix1991/8376271918/

    View Slide

  90. What are
    Design Patterns?

    View Slide

  91. View Slide

  92. “Gang of Four”

    View Slide

  93. Familiar Patterns
    Module
    Observer

    View Slide

  94. Familiar Patterns
    (but not by name)
    Singleton
    Adapter

    View Slide

  95. Not set in stone
    23 patterns in “Design Patterns”
    13 patterns in “Code Complete”
    49 patterns on WIkipedia

    View Slide

  96. Standards

    View Slide

  97. $pos = strpos($tnt_ini,'RedirectQueryIni');
    if($pos !== false){
    // Find new query ini
    function get_between($input, $start, $end) {
    return substr($input, strlen($start)+strpos($input, $start), (strlen($input) -
    strpos($input, $end))*(-1));
    }
    $new_ini = trim(get_between($tnt_ini, 'RedirectQueryIni', "\n"));
    if(empty($new_ini)) {
    $new_ini = trim(substr($tnt_ini, $pos+strlen('RedirectQueryIni')+1));
    $pos = strpos($new_ini, "\n");
    if($pos !== false) {
    $new_ini = $url;
    }
    }
    !
    // Compare with existing
    if($new_ini!=$url)
    {
    // Update tnt_orgs with new ini
    $this->db
    ->set('tnt_org_ini', $new_ini)

    View Slide

  98. You shouldn’t be able to identify
    who wrote a piece of code just by
    looking at it.

    View Slide

  99. Sublime Text is not
    the Sistine Chapel.
    Consistency over
    cleverness.

    View Slide

  100. def. Standards
    agreements within any group to
    adhere to a convention. Benefits:
    consistency, interoperability,
    comprehension

    View Slide

  101. PSRs (FIG)

    View Slide

  102. PSRs (FIG)
    PSR-0/4: Autoloading

    View Slide

  103. PSRs (FIG)
    PSR-0/4: Autoloading
    PSR-1 & PSR-2: Coding Standards

    View Slide

  104. PSRs (FIG)
    PSR-0/4: Autoloading
    PSR-1 & PSR-2: Coding Standards
    PSR-3: Logger Interface

    View Slide

  105. PHPCS
    http://philsturgeon.co.uk/blog/2013/08/php-static-analysis-in-sublime-text

    View Slide

  106. How do I get started?

    View Slide

  107. read
    Gang of Four
    Head First Design Patterns
    PHP Objects, Patterns, and Practice
    Brandon Savage’s “PHP Design Patterns”

    View Slide

  108. skim
    read your old code

    View Slide

  109. consider
    next time you write

    View Slide

  110. standardize
    create internal standards

    View Slide

  111. !
    // Located in /lib/Karani/Contacts/Name.php
    !
    class Name
    {
    protected $contact_array;
    protected $contact;
    protected $options;
    !
    public function __construct(array $contact_array, array $options = array())
    {
    $this->contact_array = $contact_array;
    $this->options = $options;
    $this->processContactArray();
    }
    !
    public function output()
    {
    return $this->getFullName();
    }
    !
    protected function getFullName()
    {
    if ($this->hasSpouse()) {
    return $this->getFullNameWithSpouse();
    PSR-4 Name Class
    !
    $name = new Karani\Contacts\Name(
    $array_of_name_stuff_from_sql
    );
    echo $name->output();
    Example use:

    View Slide

  112. Lone cowboys
    vs.
    Jetsons

    View Slide

  113. Play nice with others
    Composer, Packagist, & Code Reuse
    LESSON 3

    View Slide

  114. Sharing just got easy

    View Slide

  115. What's a Package
    Manager?

    View Slide

  116. History of PHP
    shareability
    PEAR
    PHPScripts.org
    Composer

    View Slide

  117. {
    "name": "mattstauffer/peersconf",
    "description": "PeersConf Demo",
    "require": {
    "nesbot/carbon": "1.6.*",
    "php": ">=5.3.0",
    "laravel/framework": "4.0.*",
    "dflydev/markdown": "1.0.*",
    "iron-io/iron_mq": "1.4.*",
    "filp/whoops": "1.0.*",
    "bugsnag/bugsnag": "2.*",
    "mockery/mockery": "0.*",
    "psr/log": "1.0.*",
    "imagine/imagine": "v0.5.0",
    "iron-io/iron_worker": "1.4.1"
    },
    "autoload": {
    "psr-0": {
    "PeersConf": "application/",
    },
    },
    "config": {
    },
    "require-dev": {
    "fzaninotto/Faker": "dev-master",
    "phpunit/phpunit": "3.7.*"
    composer.json

    View Slide

  118. Next Time You Need a
    Package/Library

    View Slide

  119. View Slide

  120. View Slide

  121. How do I use
    Composer today?

    View Slide

  122. In my CMS...
    Plugins
    Dukt & Exp:resso for EE examples
    Craft: Adrian Macneil “Cocktail Recipes”
    TD’s Craft Guzzle for wrapping packages

    View Slide

  123. In my app...
    Built into Laravel, Slim, Silex, Yii,
    Symfony2, ZF2
    Can be done in CI

    View Slide

  124. A few packages to try out
    • Guzzle
    • Twig
    • Carbon
    • Monolog

    View Slide

  125. Lone cowboys
    vs.
    Jetsons

    View Slide

  126. Be lazy
    Delegating to third-party SAAS apps
    LESSON 4

    View Slide

  127. Lone cowboys don’t delegate well.

    View Slide

  128. Rails FTW
    on delegation

    View Slide

  129. Karani + PDF
    PrinceXML
    $3800
    Docraptor
    $.02-$.08/sheet

    View Slide

  130. (also)
    gridonic/princexml-php

    View Slide

  131. The benefits of
    3rd party services

    View Slide

  132. Limit the
    requirements of your
    domain knowledge
    The benefits of
    3rd party services

    View Slide

  133. Distribute
    usefulness to
    whole company
    The benefits of
    3rd party services

    View Slide

  134. Auto-all-the-things
    The benefits of
    3rd party services

    View Slide

  135. Consistency
    The benefits of
    3rd party services

    View Slide

  136. Worth trying:

    View Slide

  137. iron.io

    View Slide

  138. mailgun/mandrill/sendgrid

    View Slide

  139. bugsnag/getsentry

    View Slide

  140. New Relic

    View Slide

  141. TravisCI, Coveralls

    View Slide

  142. Scrutinizer/Sensio Labs
    Insights/CodeClimate

    View Slide

  143. Lone cowboys
    vs.
    Jetsons

    View Slide

  144. Cover your butt
    Testing & TDD
    LESSON 5

    View Slide

  145. You’ve heard you
    should test…

    View Slide

  146. What is
    (automated software)
    testing?

    View Slide

  147. The Matt Stauffer Authorized Definition
    Testing: Making sure a piece of code
    does what it's supposed to, so you can
    find out if it’s broken*now*, rather than
    when an angry customer emails you.

    View Slide

  148. Benefits of testing

    View Slide

  149. 1. Catch bugs in dev

    View Slide

  150. 2. Refactor with Confidence

    View Slide

  151. !
    class nameTest extends CIUnit_TestCase
    {
    public function testHandlesSimpleIndividual()
    {
    $output_name = 'John Doe';
    !
    $name = new Name($this->simple_john_doe, array());
    !
    $this->assertEquals($output_name, $name->output());
    }
    !
    public function testHandlesSimpleIndividualReversed()
    {
    $output_name = 'Doe, John';
    !
    $name = new Name($this->simple_john_doe, array('reversed'));
    !
    $this->assertEquals($output_name, $name->output());
    }
    !
    public function testHandlesDecoratedIndividual()
    {
    $output_name = 'Dr. John Edward Doe MD';
    !
    $name = new Name($this->decorated_john_doe, array());

    View Slide

  152. "What a pain to go back
    and write all those tests"

    View Slide

  153. What is TDD?

    View Slide

  154. TDD != testing

    View Slide

  155. Red
    Green
    Refactor

    View Slide

  156. [red example]

    View Slide

  157. View Slide

  158. How do I get started
    with testing?

    View Slide

  159. 1. PHPUnit

    View Slide

  160. 2. Write tests for
    all bug fixes

    View Slide

  161. 3. Write tests for
    all new code

    View Slide

  162. 4. Stick with just
    unit tests for now

    View Slide

  163. How do I get started
    in my
    environment?

    View Slide

  164. Laravel: Built in

    View Slide

  165. Craft: Built in
    (check out adrian macneil)

    View Slide

  166. CodeIgniter:
    It can be done
    https://bitbucket.org/kenjis/my-ciunit

    View Slide

  167. ExpressionEngine:
    It can be done, ish
    Stephen Lewis & Testee

    View Slide

  168. Lone cowboys
    vs.
    Jetsons

    View Slide

  169. View Slide

  170. Outro

    View Slide

  171. Recap

    View Slide

  172. Recap
    1. Embrace the object

    View Slide

  173. Recap
    1. Embrace the object
    2. Learn from those who came before you

    View Slide

  174. Recap
    1. Embrace the object
    2. Learn from those who came before you
    3. Play nice with others

    View Slide

  175. Recap
    1. Embrace the object
    2. Learn from those who came before you
    3. Play nice with others
    4. Be lazy

    View Slide

  176. Recap
    1. Embrace the object
    2. Learn from those who came before you
    3. Play nice with others
    4. Be lazy
    5. Cover your butt

    View Slide

  177. Advanced stuff

    View Slide

  178. Exceptions

    View Slide

  179. HHVM

    View Slide

  180. Hack

    View Slide

  181. Vagrant

    View Slide

  182. Gitflow & PRs

    View Slide

  183. Chef/Puppet/
    Capistrano/Envoy

    View Slide

  184. IRC
    (party like it’s 1999)

    View Slide

  185. PHP 5.4
    built in php server
    traits
    short array syntax
    function array dereferencing

    View Slide

  186. PHP 5.5
    generators
    try/catch/finally
    foreach(list)
    expressions as empty() args
    Array/string dereferencing
    classname via ::class (alias get_class)

    View Slide

  187. PHP 5.6
    Variadic functions
    Argument unpacking
    Constants assigned to expressions
    Import namespaced functions

    View Slide

  188. View Slide

  189. View Slide

  190. View Slide

  191. Follow the FIG

    View Slide

  192. One Final Note
    This is not what you “should do” because it’s nice.
    !
    This is what you “should do” because if you do it your
    life will be better and you will make more money.

    View Slide

  193. Writing modular, reusable code.
    Not reinventing the wheel.
    No lone cowboys.
    Learning from our peers & predecessors.
    Finding the bugs before the clients do.
    Having confidence to make changes in the future.
    Reducing code rot & technical debt.
    Making life easier.
    Thanks. @stauffermatt

    View Slide