Version 4 supported
This version of Silverstripe CMS is still supported though will not receive any additional features. Go to documentation for the most recent stable version.

PHP coding conventions

This document provides guidelines for code formatting and documentation to developers contributing to Silverstripe. It applies to all PHP files in the framework/ and cms/ modules, as well as any supported additional modules.

Coding standards are an important aspect for every software project, and facilitate collaboration by making code more consistent and readable.

If you are unsure about a specific standard, imitate existing Silverstripe code.

PSR-2

Starting with Silverstripe 4.x, our goal is PSR-2 Coding Standards compliance. Since this affects existing APIs, some details like method casing will be iterated on in the next releases. For example, many static methods will need to be changed from lower underscore to lower camel casing.

Spelling

All symbols and documentation should use UK-English spelling (e.g. "behaviour" instead of "behavior"), except when necessitated by third party conventions (e.g. using PHP's Serializable interface).

Configuration variables

Silverstripe's Config API can read its defaults from variables declared as private static on classes. As opposed to other variables, these should be declared as lower case with underscores.

namespace App;

class MyClass
{
    private static $my_config_variable = 'foo';
}

Prefer identical (===) comparisons over equality (==)

Where possible, use type-strict identical comparisons instead of loosely typed equality comparisons. Read more in the PHP documentation for comparison operators and object comparison.

// good - only need to cast to (int) if $a might not already be an int
if ((int)$a === 100) {
    doThis();
}

// bad
if ($a == 100) {
    doThis();
}

Separation of logic and presentation

Try to avoid using PHP's ability to mix HTML into the code.

// PHP code
public function getTitle()
{
    return '<h2>Bad Example</h2>';
}
// Template code
$Title

Better: Keep HTML in template files:

// PHP code
public function getTitle()
{
    return 'Better Example';
}
// Template code
<h2>$Title</h2>

Comments

Use phpdoc syntax before each definition (see tutorial and tag overview).

  • Methods should include at least @param and @return.
  • Include a blank line after the description.
  • Use {@link MyOtherClass} and {@link MyOtherClass->otherMethod} for inline references.
  • Denote preformatted code examples in <code></code> blocks.
  • Always start block-level comments containing phpdoc with two asterisks (/** ... */).

Example:

namespace App;

/**
 * My short description for this class.
 * My longer description with
 * multiple lines and richer formatting.
 *
 * Usage:
 * <code>
 * $c = new MyClass();
 * $c->myMethod();
 * </code>
 *
 * @package custom
 */
class MyClass extends Class
{
    /**
     * My Method.
     * This method returns something cool. {@link MyParentMethod} has other cool stuff in it.
     *
     * @param string $colour The colour of cool things that you want
     * @return DataList A list of everything cool
     */
    public function myMethod($colour)
    {
        // ...
    }
}

Class member ordering

Put code into the classes in the following order (where applicable).

  • Static variables
  • Member variables
  • Static methods
  • Data-model definition static variables. ($db, $has_one, $many_many, etc)
  • Commonly used methods like getCMSFields()
  • Accessor methods (getMyField() and setMyField())
  • Controller action methods
  • Template data-access methods (methods that will be called by a $MethodName or <% loop $MethodName %> construct in a template somewhere)
  • Object methods

Method/property visibility guidelines

When adding new methods and properties, should you make them public, protected, or private?

  • Public: Use this for public APIs. You should add tests and documentation for these.
  • Protected: Use for extensibility APIs. Note that compatibility for such APIs should be maintained in minor releases, and so you'll probably want to cover them in tests (i.e. test that these methods can be called from within a subclass and/or overridden). If that seems like overkill, consider whether it's safer to leave these as private for now.
  • Private: Use for class internals

Above all, recognise that when you are making something public or protected, you are creating an API for other developers to use and rely on, and do so with care. Don't simply dump class internals in as protected members in the name of extensibility – doing so will be likely to break developers' projects in minor releases.

SQL format

If you have to use raw SQL, make sure your code works across databases. Make sure you escape your queries like below, with the column or table name escaped with double quotes as below.

MyClass::get()->where(['"Score" > ?' => 50]);

It is preferable to use parameterised queries whenever necessary to provide conditions to a SQL query, where values placeholders are each replaced with a single unquoted question mark. If it's absolutely necessary to use literal values in a query make sure that values are single quoted.

MyClass::get()->where("\"Title\" = 'my title'");

Use ANSI SQL format where possible.

Secure development

See security for conventions related to handing security permissions.

Related