5 PHP Coding Standards You Will Love And How To Use Them

  • Post author:
  • Post last modified:2021-01-15
  • Post category:Code Review
  • Reading time:16 mins read

Table of Contents

  1. PSR-2 Coding Style Guide
  2. CakePHP Coding Standards
  3. Symfony Coding Standards
  4. WordPress Coding Standards
  5. FuelPHP Coding Standards
  6. Referenced Articles

Setting a coding standard is very important in team development. Agreeing on one coding standard helps keep your code neat and easy to read and also makes it easy to see the difference in your code when reviewing them. Unfortunately, coding standards for PHP are different between frameworks and PHP versions. For example, method names are to be written in various styles, such as camelCase, snake_case and so on. Rules for naming namespaces and classes and how to use indents and spaces are also different. In this article, we will introduce several well-known PHP coding standards.

1. PSR-2 Coding Style Guide

About PSR

PSR is a standard established by PHP-FIG(PHP Framework Interop Group). PHP has various frameworks and libraries such as Zend Framework and Symfony, but all have slightly different coding standards. So PHP-FIG, having involved members from each framework, established a coding standard that could be used for all PHP frameworks…PSR.

PSR consists of several standards such as PSR-1, PSR-2 and PSR-4. PSR-0 and PSR-4 are coding standards for PHP’s autoloaders, and PSR-1 and PSR-2 are basic coding standards. Currently, PSR-2 is becoming the most common coding standard for PHP.

PSR-0 and PSR-4

PSR-0 and PSR-4 are both standards concerning namespaces, class names and file paths. Since October 2014, PSR-0 has been deprecated. PSR-4 is now recommended as an alternative. https://www.php-fig.org/psr/psr-0/ Since PHP has an autoload mechanism, each class name with a namespace must have one corresponding file path.

PSR-0

In PSR-0, the following rules are defined for the correspondence between class names with a namespace and file paths:

  • Replace in namespaces with directory separator /
  • Replace _ in class names with directory separator /
  • Add .php to the end

For example, correspondence between class names and file paths are as below:

Class Name with NamespaceCorresponding File PathNotesvendornamenamespaceClassName/project/path/namespace/ClassName.php are replaced with /vendornamename_spaceClassName/project/path/name_space/ClassName.php_ in namespaces don’t have any special meaningvendornamename_spaceClass_Name/project/path/name_space/Class/Name.php_ in class names are replaced with /

PSR-4

PSR-4 is a new standard replacing PSR-0. Major changes are:

  • _ in class names don’t have any special meaning

Therefore, file paths corresponding to vendornamename_spaceClass_Name are

  • PSR-0: /project/path/name_space/Class/Name.php
  • PSR-4: /project/path/name_space/Class_Name.php

Why there are both PSR-0 and PSR-4

Namespaces for PHP were implemented from PHP5. Namespaces don’t exist in previous PHP versions. When there were no namespaces, there was a problem where class names often conflicted.

For example, you couldn’t define a class named ‘Mysql’ if there was another class defined by that name in one of your imported libraries. In such situations, the common practice was to add a prefix with the project’s name, like Zend_Mysql. PSR-0 made it able to handle such class names with prefixes like namespaces.

Like this, PSR-0 is a standard made to work with older codes. Even though it is deprecated, there might be a chance PSR-0 is more suitable than PSR-4 when using old PHP. However, using PSR-4 is recommended for new projects.

PSR-1 Basic Coding Standard

The more basic parts of PHP coding standards are defined in PSR-1. For example:

  • Only <?php or <?= are allowed for PHP tags
  • Files must be in UTF-8 without BOM(Byte Order Mark)
  • Namespaces and class names must follow the standards in PSR-0 and PSR-4
  • Class names must be defined in UpperCamelCase
  • Class variables must be defined in UPPER_SNAKE_CASE
  • Method names must be defined in camelCase

Standard functions in PHP are defined in snake_case, but in PSR-1, method names must be defined in camelCase. There are no explicit rules for variable and property names, so you can use whichever style you like, but it is noted that they should be consistent. For example, defining normal properties in camelCase and static properties in UpperCamelCase like below:

class Something
{
    public $normalPropterty;
    public static $StaticProperty;
}

PSR-2 Coding Style Guide

PSR-2 is an extension of the PSR-1 coding standard. Some examples of its contents are:

  • You must follow PSR-1 coding standards
  • 4 spaces must be used for indents. Using tabs is not allowed
  • There is no limit to line length, but it should be under 120 characters, and best if under 80
  • You must put a newline before curly braces for classes and methods
  • Methods and properties must be defined with abstract/final first, followed with public/protected, and finally static.
  • You must not put a newline before curly braces in conditional statements
  • You must not put any spaces before ( and ) in conditional statements

CakePHP and Symfony, which will be explained later on in this article, are based on this PSR-2 standard.

Defining Classes

You must put a newline before { in class definitions. Also, extends and implements must be written on the same line as the class name.

class ClassName extends ParentClassName implements Interface1, Interface2
{
    // Class definition
}

If there are too many interfaces for one line, you should put a newline after implements and write one interface per line like below.

class ClassName extends ParentClassName implements
    Interface1,
    Interface2,
    Interface3,
    Interface4
{
    // Class definition
}

Since there are quite a few standards that recommend writing { on the same line like class ClassName {, this may be a style which you haven’t seen before.

Defining Properties

In PSR-2, you must not omit public/protected/private modifiers. In PHP, properties become public if these are omitted, but because it is hard to tell if one purposely omitted these modifiers or they just forgot, you should always explicitly write public. The static keyword comes next. You must not use var when defining properties because you can’t add any modifiers to var.

class ClassName
{
    public $property1;
    private $property2;
    public static $staticProperty;
}

Additionally, you must not define two or more properties with one statement. You can define properties in the way shown below but it is prohibited in PSR-2.

class ClassName
{
     private $property1, $property2;
}

Methods

Like properties, you must have either one of public/protected/private and abstract/final comes after them if used. static is the last modifier. You must not put any spaces before and after braces, and you must put a newline before curly braces. Also, you must not put any whitespaces before commas in arguments, and you must put one whitespace after them.

class ClassName
{
    abstract protected function abstractDoSomething();
    final public static function doSomething($arg1, $arg2, $arg3)
    {
        // ...
    }
}

If there are too many arguments, you can put a newline after ( and write one argument per line. In this case, you can’t write multiple variables on one line. Also, you should write ) and { on the same line, separated by a whitespace.

class ClassName
{
    public function doSomething(
        TypeHint $arg1,
        $arg2,
        $arg3,
        $arg4
    ) {
        // ...
    }
}

Please note that you must not put a newline before { in closures.

$closure = function ($a, $b) use ($c) {
    // Body
};

Conditional Statements

For conditional statements,

  • You must put one whitespace before (
  • You must not put any whitespaces after (
  • You must not put any whitespaces before )
  • You must put one whitespace after )

Also, use elseif rather than else if.

if ($condition1) {
    // ...
} elseif ($condition2) {
    // ...
} else {
    // ...
}

Be careful, else if and elseif are not the complete same things. elseif is one statement by itself, but else if on the other hand is interpreted as an if statement in the else of the first if.

if ($condition1) {
    // ...
} else if ($condition2) {
    // ...
} else {
    // ...
}

The syntax above is actually interpreted like below:

if ($condition1) {
    // ...
} else {
    if ($condition2) {
        // ...
    } else {
        // ...
    }
}

For switch statements, case statements must be indented once from switch, and bodies for the cases must be indented once from case. When not breaking after any kind of operations in case, you must write a comment.

switch ($condition) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

2. Cake PHP Coding Standards

About CakePHP

CakePHP is an open source web framework. Many long web services are likely to be using CakePHP. Since developers from CakePHP participate in PHP-FIG, the standards basically follow PSR-2. However, there are a few additional standards to be followed.

Line Length

PSR-2 recommends lines to be under 120 characters, but this was not required. However, in CakePHP coding standards, lines are recommended to be under 100 letters and are required to be under 120 letters.

Ternary Operators

You must not nest ternary operators.

$variable = isset($options['variable']) ? isset($options['othervar']) ? true : false : false;

Nesting ternary operators makes your code hard to read. It becomes harder to understand what is evaluated first and what value is returned. You should use ‘if’ statements and write them more clearly.

$variable = false;
if(isset($options['variable']) && isset($options['othervar'])) {
    $variable = true;
}

Comparison

For comparison, you should use strict comparison (===!==) whenever possible.

if ($value === null) {
    // ...
}

PHP supports not only strict comparison but also loose comparison (==!=). Types are cast when loosely comparing primitive types. This behavior is useful in some ways but may result in returning unexpected true results.

$value = 0;
if ($value == null) {
    // null becomes 0 when cast to int
    // The comparison returns true, so the body is executed
}

Also, you should have the check target of the comparison on the right.

// not recommended(called Yoda notations, or Yoda conditions)
if (null === $value) {
    // ...
}
// recommended
if ($value === null) {
    // ...
}

Writing the check target on the left is called a Yoda notation. If the === was to be mistaken with =, $value = nulldoesn’t result in an error, but null = $value does. Because of this, Yoda notations are said to reduce bugs. However, Yoda notations are not recommended in the CakePHP coding standard, especially when considering code legibility.

3. Symfony Coding Standard

About Symfony

Symfony is another fairly old open source web framework, like CakePHP. Similarly, the developers participate in PHP-FIG, so the standards again basically follow PSR-2 and have a few additional standards. However, the additional standards follow a slightly different mindset.

Use Yoda Notations for Comparisons

Using Yoda notations is recommended when using comparisons with ==, ===!=!==, etc.. This is the complete opposite from CakePHP.

// recommended(called Yoda notations, or Yoda conditions)
if (null === $value) {
    // ...
}
// not recommended(was recommended in CakePHP)
if ($value === null) {
    // ...
}

As stated in the CakePHP chapter, writing comparisons like $value === null do not result in an error when mistaking === with =, and is hard to notice such bugs. Therefore, Yoda notations are recommended in Symfony.

Put a Comma after the Last Element of Arrays Taking Multiple Lines

The following two styles of writing arrays result in the same values. However, the first style is recommended.

// recommended style
$array = [
    'value1',
    'value2',
    'value3', // comma at the end of last line
];
// not recommended
$array = [
    'value1',
    'value2',
    'value3'  // no comma at the last line
];

This is because it is easier to read the differences when adding elements.

// recommended
 $array = [
     'value1',
     'value2',
     'value3', // comma at the end of last line
+    'value4', // only this line is shown as the difference
 ];
 // not recommended
 $array = [
     'value1',
     'value2',
-    'value3'  // no comma at the last line
+    'value3', // no comma at the last line
+    'value4'  // the line above is also shown as the difference
 ];

With the unrecommended style, one more line shows up as the difference since you have to add a comma to the former last line. If an array takes multiple lines, you should also put a comma after the last element.

Write Arguments on the Same Line as Method or Function Names

You should write arguments for methods and functions on the same line as the method or function names.

public function doSomething($arg1, $arg2, $longNameArgument3, $longNameArgument4, $longNameArgument5)
{
    // ...
}

This rule is considered to be intended to restrain method and function definitions with long arguments and to increase code legibility by making it easier to distinguish the function’s arguments and body. However, this also results in longer lines. This may be a rule that goes a different way from CakePHP, which restricts the length of a line.

The Order of Properties/Methods in a Class

In a class, properties are defined first, and then the methods. For the order of properties and methods, public methods come first, then protected, and finally private. Among the methods, constructors (__construct()), PHPUnit, setUp() and tearDown() are defined first.

class Something
{
    public $property1;
    protected $property2;
    private $property3;
    public function __construct()
    {
        // ...
    }
    public function doSomething()
    {
        // ...
    }
    private function doSomethingPrivate()
    {
        // ...
    }
}

Prefixes and Suffixes for Classes

You should add an Abstract suffix to an abstract class.

abstract class AbstractDatabase
{
    // ...
}

You should add an Interface suffix to an interface.

interface LoggerInterface
{
    // ...
}

You should add a Trait suffix to a trait.

trait SomethingTrait
{
    // ...
}

You should add an Exception suffix to an exception.

class NotFoundException extends RuntimeException
{
    // ...
}

4. WordPress Coding Standard

About WordPress

WordPress is an open source software written in PHP mainly used to create blogs. This is another fairly old framework, but there are still many blogs and websites created with WordPress. Since there are no WordPress developers participating in PHP-FIG, the coding standards follow a different mindset than that of PSR.

Use Tabs for Indents

In the WordPress Coding Standard, it is stated that you should use tabs for indents, not spaces. However, using whitespaces is allowed when lining up the code lines.

[tab]$foo   = 'somevalue';
[tab]$foo2  = 'somevalue2';
[tab]$foo34 = 'somevalue3';
[tab]$foo5  = 'somevalue4';

One advantage of using tabs for indents is that you can change the indent width without changing the codes itself by changing the tab width settings of your text editor. You can accommodate preferences for different indent widths. Additionally, using one tab instead of 4 whitespaces helps reduce file size.

However, some environments may not be able to show the tabs correctly. PSR recommends four spaces for indents to rule out such environment dependencies. Fairly old codes sometimes use tabs for indents.

Whitespaces in Conditional Statements and Function Calls

You should add a whitespace before and after braces in conditional statements such as if and for.

if ( $condition ) {
    // ...
}

You should add whitespaces as shown below for function definitions and calls.

function my_function( $arg1, $arg2 ) {
    // ...
}

Use Flag Values with Meaning for Function Arguments

You must avoid function definitions such as:

function my_function( $arg1, $arg2 ) {
    // ...
}

Calling this functions will be like:

eat( 'mushrooms', true );

However, when looking at this call, we can’t tell what true actually means. You will have to go check the function’s definition to understand the meaning of this true. So, the WordPress Coding Standard recommends styles such as:

function eat( $what, $speed = 'slowly' ) {
    // ...
}

This definition will make the function call look like:

eat( 'mushrooms', 'slowly' );

Now we can tell that the function says to eat “slowly” just by looking at the call. The following style is recommended for further improvement:

function eat( $what, array $args ) {
    // ...
}

The function call will look like:

eat ( 'mushrooms', array( 'speed' => 'slowly' ) );

Now we can also tell clearly that slowly is a speed.

This style does make the functions easier to read but also has a disadvantage — -it may increase the number of bugs because mistyping the speed and slowly strings doesn’t result in an error.

5. FuelPHP Coding Standards

About FuelPHP

FuelPHP is an open source web framework written in PHP. It is slightly newer than the other introduced frameworks such as Symfony, but has standards with a different mindset than PSR.

Naming Conventions for Methods and Variables

In FuelPHP, you must use snake_case for method and variable names. Also, you must put a newline before { in classes and methods as also stated in PSR-2.

Names of private and protected methods and properties should start with an underscore.

class Session
{
    protected $_data;
    public static function get_flash($name, $data)
    {
        // ...
    }
    private function _private_metod($argument_name)
    {
        // ...
    }
}

Standard functions in PHP are defined in snake_case, so there are cases where method and variable names are accordingly made snake_case.

Starting private/protected method and property names with an underscore is a remainder of an old practice. Before PHP4, defining private methods and properties was not supported, so there was a practice to start names of private methods and properties with an underscore.

Put a Newline Before Curly Braces in Conditional Statements

In PSR-2 you were to put a newline before curly braces in class and method definitions, but there was nothing about curly braces in conditional statements. In FuelPHP, you also must put a newline before curly braces in conditional statements.

if ($condition)
{
    // ...
}

Use and and or Instead of && and ||

FuelPHP recommends you to use and and or instead of && and || in terms of code legibility.

// not this...
if ($var == false && $other_var != 'some_value')
// but this
if ($var == false and $other_var != 'some_value')

However, be careful that && and and operators have slightly different priorities.

<?php
$var = 0;
if($var = 2 && 1) {
    echo $var, PHP_EOL; // => 1
}
$var = 0;
if($var = 2 and 1) {
    echo $var, PHP_EOL; // => 2
}

= has higher priority than and, and && has higher priority than =, so the former is interpreted as $var = (2 && 1) and the value of $var becomes 1. On the other hand, the latter is interpreted as ($var = 2) and 1, so the value of $varbecomes 2. These is a pretty specific case, but is worth noting.

Summary

In this article, we introduced coding standards for several well-known frameworks and some interesting ones. Other frameworks such as Zend Framework and PEAR also have a coding standard. Especially, coding standards for old frameworks like Zend Framework tend to include rules for older versions of PHP. However, after PSR-2 had been established, the number of frameworks following PSR-2 have been increasing. Projects with older versions of PHP without any frameworks may include codes following PEAR’s standards.

When deciding on a coding standard for a new project, we recommend following PSR-1 or PSR-2 and adding a few additional rules or following the standards of the framework you are using.

After establishing a coding standard, we’re sure there are cases where your codes are checked by code reviews, etc. to ensure they are being followed. Unfortunately, having humans check the codes usually takes time and effort and result in overlooked mistakes. A tool called PHP_CodeSniffer, which automatically runs checks about coding standards, can help solve these issues. Also, by introducing Sider, you can check for coding standard violations for the codes in your Pull Requests. By integrating Sider into Github and adding your repository in sideci.yml, you can run coding standard checks with PHP_Codesniffer for your Pull Requests( https://help.sider.review/tools/php/code-sniffer ). The default standard for PHP is PSR-2, but you can check for other coding standards such as CakePHP and Symfony too.

References


For more information about Sider, please go to our website.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.