The Complete Guide to PHP: The Right Way

*Abridged

*

Chapter 1: Welcome

Chapter 1: Welcome

  • PHP doesn't (always) suck
  • There is no "right" way to write PHP (except when you're doing it wrong)

Chapter 2: Getting Started

Chapter 2: Getting Started

  • You're gonna need a PHP installation.
  • RTFM: php.net/install

Chapter 3: Code Style Guide

Chapter 3: Code Style Guide

  • Familiarize yourself with the PSRs (php-fig.org)
    • PSR-0: Autoloading
    • PSR-1: Basic coding standard
    • PSR-2: Expanded coding standard
    • PSR-3: Logger interface
    • PSR-4: Autoloading
    • PSR-6: Cache interface
    • PSR-7: HTTP message interface
  • Rely on your code editor/plugins to help you with these

Chapter 4: Language Highlights

OOP and Namespaces

Those things exist in PHP!

Functional Programming

  • First class function support
    • Function can be assigned to a variable
    • Dynamic invocation of functions
    • Functions can be passed as arguments
    • Functions can return other functions
  • Recursion!
  • Anonymous functions!
  • Ridiculously huge standard library!
  • CLI support!
  • A reasonably okay debugger!

Chapter 5: Dependency Management

Two Options:

  • Composer/Packagist
  • PEAR

Composer and Packagist

  • Learn them
  • Use them
  • Love/hate them
  • If you think "I need this code added to my project", the answer is probably Composer.

PEAR

PEAR

Chapter 6: Coding Practices

Date/Time handling

  • Use the Date* classes (DateTime, DateInterval, DatePeriod, etc)
  • Stop using date() and time()

Design Patterns

  • Use them to the extent that they make sense
  • Don't overengineer
  • Wikipedia "Design Patterns" page is a good place to start

UTF-8

  • You have to explicitly opt-in to multibyte handling
  • Use the functions provided by the Multibyte String extension (ext_mb): mb_strpos(), mb_strlen(), etc.
  • MySQL: use utf8mb4 character set and collation
  • Browser: Use UTF-8 charset, Content-Type header
  • Drupal does some of this for you

Chapter 7: Dependency Injection

<?php

class Database {
  protected $adapter;
  public function __construct() {
    $this->adapter = new  MysqlAdapter();
  }
}

class MysqlAdapter {}
<?php

class Database {
  protected $adapter;
  public function __construct(
    DatabaseAdapter $adapter
  ) {
    $this->adapter = $adapter;
  }
}

interface DatabaseAdapter {}

class MysqlAdapter implements DatabaseAdapter {}

class PgsqlAdapter implements DatabaseAdapter {}

Before

After

Dependency Injection

  • Can be done without a DI Container
  • Allows swapping out implementations of a particular piece of functionality
  • Encourages developers to write testable code
  • Not always a great idea: can lead to deep, difficult to debug dependency trees.

Chapter 8: Databases

or, "Chapter 8: Use PDO"

Databases

  • Use PDO
  • Use PDO's parameter binding
  • Don't use mysqli (mysql_*() )
  • Use PDO

Seriously: Use PDO*

*or a wrapper on top of PDO, like Drupal's DBTNG

Chapter 9: Templating

Templating

  • Don't put business logic in templates
  • You probably shouldn't roll your own templating system. Use one of the existing tools. They're all pretty good. Places to start: Twig, Blade, Plates
  • Using a template engine forces you to not put business logic in templates.

Chapter 10: Errors and Exceptions

Errors and Exceptions

  • If you have an error condition in a class method, throw an exception. SPL defines a number of Exceptions that you can use (e.g. ValidationException)
  • assert() is your friend
  • Develop with notices turned on
  • Don't use the error suppression operator when you can avoid it.
  • PHP 7's engine error conditions throw exceptions too, so you can recover from errors that would have previously been fatal.

Chapter 11: Security

Rule 1:

Do not

under

ANY

circumstances

write
your own
crypto

Rule 2:

Do NOT write your own crypto.

Crypto

  • Password hashing/obfuscation schemes: use password_hash() / password_verify()  (packagist: password_compat)
  • Random number generator: use random_bytes() / random_int()   (packagist: random_compat)
  • Encryption/decryption algorithms: use phpseclib  (NOT mcrypt).

Other appsec

  • Use filter_var() for input filtering
  • Use HTML purifier for output filtering
  • Don't unserialize() untrusted data
  • Generally: don't trust your users.

Chapter 12: Testing

Testing

  • TDD is good. Do it when you can.
  • Unit tests: write them (PHPUnit & friends)
  • Integration tests: write them (PHPUnit & friends)
  • Functional/behavioral tests tests: write them (Simpletest if you have to, Codeception, Mink, Selenium, PHPSpec, Behat)
  • You have to decide what kind of test is relevant to your task.

Code coverage numbers don't mean anything

Chapter 13: Servers and Deployment

Servers and Deployment

  • Consider where your time spent is most valuable: that's usually not managing servers.
  • Options:
    • PaaS: Pantheon, Heroku, etc.
    • VPS/Dedicated Server: Digital Ocean, Linode, etc.
    • Shared hosting: Please no, but if you have to, NearlyFreeSpeech.net is the least bad.

Build automation

  • Run your test suite on every commit/PR
  • Jenkins helps with that. See also: Drone.io, Travis CI
  • If tests pass, consider automatically deploying with something like Deployer, Capistrano, Fabric, or Phing (I guess). For open source, Travis CI also handles deployments for free.

Chapter 14: Virtualization

Virtualization

  • Usually, you shouldn't use the PHP installed on your workstation.
  • Use Vagrant or similar to mimic your production environment.
  • Docker can be helpful. Can also be a huge PITA.

Chapter 15: Caching

Caching

  • Opcode cache: opcache included in PHP since 5.5. APC for earlier versions.
  • Object cache: APCu is good. Also consider Redis, Memcached, or (shudder) WinCache.

Chapter 16: Documenting your code

Use PHPDoc

<?php
/**
 * @author A Name <a.name@example.com>
 * @link http://www.phpdoc.org/docs/latest/index.html
 */
class DateTimeHelper {
    /**
     * @param mixed $anything Anything that we can convert to a \DateTime object
     *
     * @throws \InvalidArgumentException
     *
     * @return \DateTime
     */
    public function dateTimeFromAnything($anything){}
}

It looks like this:

RTFM at phpdoc.org

End.

More details at http://www.phptherightway.com

The complete guide to PHP: The Right Way (Abridged)

By Cameron Eagans

The complete guide to PHP: The Right Way (Abridged)

  • 673