Skip to content

Instantly share code, notes, and snippets.

@ameliaikeda
Last active August 29, 2015 14:18
Show Gist options
  • Save ameliaikeda/559c589564185778a496 to your computer and use it in GitHub Desktop.
Save ameliaikeda/559c589564185778a496 to your computer and use it in GitHub Desktop.
PHP Coding Style Guide

PHP Style Guide

Firstly: follow PSR-1, PSR-2 and PSR-4 strictly.

4 spaces instead of tabs. \n for newlines.

Specific Rules

Properties

An explicit mention for PSR-2 Section 4.2

Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility.

Instead, Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. They are already protected/private.

There is no reason to do this; we're not using a language with public-only access (e.g. Python), and if you want to access a private/protected member from outside you'd use reflection regardless and would be breaking every coding standard ever, as well as encapsulation.

Namespace Declaration

On the same line as <?php

<?php namespace Foo\Bar;

class Baz {
    //
}

DocBlocks

Always use PHPDoc blocks. The minimum for a method/function is an @return tag, while the minimum for a class member is an @var <type> tag.

Exception: @return is not required for __construct.

Always declare @var, not @type, and always on multiple lines. Try to include a description.

Aka prefer this:

/**
 * Internal items for this collection
 *
 * @var array
 */
 protected $items;

And never do this:

/** @var array */
protected $items;

SOLID

Wikipedia Article Here

Follow this. It stands for:

  • Single Responsibility Principle
  • Open/Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle (not explicitly injection)

In short (in order):

  • Classes must only do one thing.
  • Classes should be open for extension (think protected access), but closed for modification; this means follow semver and don't go changing a class at will.
  • Classes should implement an interface (contract); anything implementing that interface should be swappable at will in an IoC container or service locator.
  • Many interfaces for specific tasks always always beat once big interface for many tasks.
  • Let classes define their dependencies to an interface, preferrably with an IoC container and reflection. See below.

Dependency Inversion (of Control)

<?php namespace Foo\Bar;

use Foo\Something\FooInterface;

class Baz implements BazInterface {

    /**
     * Foo Instance or something
     *
     * @var \Foo\Something\FooInterface
     */
    protected $foo;

    /**
     * Make a new Baz instance using a Foo-like object
     *
     * @param \Foo\Something\FooInterface $foo
     */
     public function __construct(FooInterface $foo)
     {
        $this->foo = $foo;
     }
}

Write classes like this. Let an IoC container or reflection automatically associate the interface needed with a concrete class and inject it.

This also means you can inject a mock into the class when testing.

Testing

Code should be tested. The easiest tests to set up with frameworks are functional tests, but a library that (for example) uses a lot of math should be unit tested and functional tested strictly.

Default to PHPUnit for testing, but PHPSpec, Behat, etc. can all be used. Just make sure they are in the require-dev section of your composer.json so that people can install and run them locally instead of globally.

Write tests before you start writing a class or it's not TDD!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment