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.

60187fe0ab07ea5a46572a3ab05f61dd?s=128

Matt Stauffer

April 25, 2014
Tweet

Transcript

  1. Modern PHP is Amazing You Can Use It Today @stauffermatt

    A N D Why How
  2. Matt Stauffer @stauffermatt

  3. Gainesville

  4. My history Graphic Design

  5. My history Graphic Design Frontend

  6. My history Graphic Design Frontend Hacky PHP & Wordpress

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

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

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

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

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

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

    Expression Engine Rails Laravel General Good Developer-y Stuff Left for 5 years
  13. Who are we?

  14. Who are we? Self-taught

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

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

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

    companies “Lone cowboy” types*
  18. Our tools are holding us back. THE PROBLEM:

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

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

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

    Fix (or ditch) them. THE SOLUTION:
  22. Disclaimers:

  23. Disclaimers: 1. You might already know this

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

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

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

    be totally overwhelming 3. Easiest in modern environments 4. One size fits some
  27. 5 LESSONS TO MAKE YOUR PHP BETTER

  28. Embrace the Object Object Oriented PHP LESSON 1

  29. Classic PHP is { procedural }

  30. <?php require_once("common.inc"); $page_slug = getPageSlug($_GET); $page_title = getPageTitle($page_slug); ! include_once("templates/header.inc");

    ! echo getHeaderNav($page_slug); ! // ... Procedural PHP
  31. <?php 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
  32. <?php 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
  33. <?php 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
  34. <?php 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
  35. <?php 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
  36. <?php 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
  37. <?php 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
  38. <?php 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
  39. <?php 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
  40. ! ! ! ! ! <!-- View file: --> !

    <h1><?= $item->title; ?></h1> ! <h2>Images</h2> ! <ul class="slider"> <?php foreach ($item->getRelatedImages() as $image): ?> <li><img src="<?= $image->url; ?>" alt="<?= $image->alt; ?>"></li> <?php endforeach; ?> </ul>
  41. PHP is an OOP late bloomer 2007 2015 2011 2003

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

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

    1999 1995 PHP 5.3 (true OOP) PHP released 1995
  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
  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
  46. CodeIgniter taught me OOP

  47. CodeIgniter taught me OOP some OOP-y things

  48. 1) Separation of Concerns (MVC)

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

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

    functions
  51. CodeIgniter Developer != (necessarily) OOP Developer

  52. brandon ruined me

  53. What OOP isn’t

  54. What OOP isn’t Taking all of your old DB- related

    functions & bundling them into a "model"
  55. Taking all of your old functions & bundling them into

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

    isn’t
  57. What OOP is

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

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

  60. Foundations Of OOP

  61. Interfaces

  62. SOLID

  63. SOLID 1. Single Responsibility

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

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

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

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

    Interface Segregation 5. Dependency Inversion
  68. thing2 thing1 Tight Coupling

  69. thing2 thang thing1 Tight Coupling

  70. thing2 thing1 injected Off Limits Law of Demeter

  71. Why OOP?

  72. Sharing & Reuse Why OOP?

  73. Lower cost of debug Why OOP?

  74. Lower cost of comprehension Why OOP?

  75. Limited interfaces Why OOP?

  76. Lower cost of change Why OOP?

  77. Refactor Time

  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'];
  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
  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();
  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();
  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();
  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();
  84. <?php ! 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 <?php ! include_once('ContactName.php'); ! $name = new ContactName( $array_of_name_stuff_from_sql ); echo $name->output(); Example use:
  85. Instant Re-use

  86. Lone cowboys vs. Jetsons

  87. Learn from those who came before you Design Patterns &

    Coding Standards LESSON 2
  88. Design Patterns

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

  90. What are Design Patterns?

  91. None
  92. “Gang of Four”

  93. Familiar Patterns Module Observer

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

  95. Not set in stone 23 patterns in “Design Patterns” 13

    patterns in “Code Complete” 49 patterns on WIkipedia
  96. Standards

  97. <?php $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)
  98. You shouldn’t be able to identify who wrote a piece

    of code just by looking at it.
  99. Sublime Text is not the Sistine Chapel. Consistency over cleverness.

  100. def. Standards agreements within any group to adhere to a

    convention. Benefits: consistency, interoperability, comprehension
  101. PSRs (FIG)

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

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

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

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

  106. How do I get started?

  107. read Gang of Four Head First Design Patterns PHP Objects,

    Patterns, and Practice Brandon Savage’s “PHP Design Patterns”
  108. skim read your old code

  109. consider next time you write

  110. standardize create internal standards

  111. <?php namespace Karani\Contacts; ! // 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 <?php ! $name = new Karani\Contacts\Name( $array_of_name_stuff_from_sql ); echo $name->output(); Example use:
  112. Lone cowboys vs. Jetsons

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

    3
  114. Sharing just got easy

  115. What's a Package Manager?

  116. History of PHP shareability PEAR PHPScripts.org Composer

  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
  118. Next Time You Need a Package/Library

  119. None
  120. None
  121. How do I use Composer today?

  122. In my CMS... Plugins Dukt & Exp:resso for EE examples

    Craft: Adrian Macneil “Cocktail Recipes” TD’s Craft Guzzle for wrapping packages
  123. In my app... Built into Laravel, Slim, Silex, Yii, Symfony2,

    ZF2 Can be done in CI
  124. A few packages to try out • Guzzle • Twig

    • Carbon • Monolog
  125. Lone cowboys vs. Jetsons

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

  127. Lone cowboys don’t delegate well.

  128. Rails FTW on delegation

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

  130. (also) gridonic/princexml-php

  131. The benefits of 3rd party services

  132. Limit the requirements of your domain knowledge The benefits of

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

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

  135. Consistency The benefits of 3rd party services

  136. Worth trying:

  137. iron.io

  138. mailgun/mandrill/sendgrid

  139. bugsnag/getsentry

  140. New Relic

  141. TravisCI, Coveralls

  142. Scrutinizer/Sensio Labs Insights/CodeClimate

  143. Lone cowboys vs. Jetsons

  144. Cover your butt Testing & TDD LESSON 5

  145. You’ve heard you should test…

  146. What is (automated software) testing?

  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.
  148. Benefits of testing

  149. 1. Catch bugs in dev

  150. 2. Refactor with Confidence

  151. <?php ! 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());
  152. "What a pain to go back and write all those

    tests"
  153. What is TDD?

  154. TDD != testing

  155. Red Green Refactor

  156. [red example]

  157. None
  158. How do I get started with testing?

  159. 1. PHPUnit

  160. 2. Write tests for all bug fixes

  161. 3. Write tests for all new code

  162. 4. Stick with just unit tests for now

  163. How do I get started in my environment?

  164. Laravel: Built in

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

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

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

  168. Lone cowboys vs. Jetsons

  169. None
  170. Outro

  171. Recap

  172. Recap 1. Embrace the object

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

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

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

    came before you 3. Play nice with others 4. Be lazy
  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
  177. Advanced stuff

  178. Exceptions

  179. HHVM

  180. Hack

  181. Vagrant

  182. Gitflow & PRs

  183. Chef/Puppet/ Capistrano/Envoy

  184. IRC (party like it’s 1999)

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

    function array dereferencing
  186. PHP 5.5 generators try/catch/finally foreach(list) expressions as empty() args Array/string

    dereferencing classname via ::class (alias get_class)
  187. PHP 5.6 Variadic functions Argument unpacking Constants assigned to expressions

    Import namespaced functions
  188. None
  189. None
  190. None
  191. Follow the FIG

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