Potherca
9/26/2013 - 7:20 PM

Popular Coding Convention in PHP on Github - Shortlist

Popular Coding Convention in PHP on Github - Shortlist

Whitespace

File Encoding

File encoded uses ISO-8859-1

File encoded uses UTF-8

Brace Placement (Class)

Class opening/closing braces on seperate line (Allman)

class Foo 
{
    // ...
}

Class structure opening/closing braces on same line as declaration (OTBS)

class Foo {
    // ...
}

Brace Placement (Control Structures)

Control structure opening/closing braces on same line as declaration (OTBS)

if($baz) {
    // ..
} else {
    // ..
}    

Control structure braces on same line as declaration, except for closing brace (Stroustrup)

if($baz) {
    // ..
}
else {
    // ..
}    

Control structure opening/closing braces on seperate line from declaration (Allman)

if($baz)
{
    // ..
} 
else 
{
    // ..
}    

Brace Placement (Methods)

Method opening/closing braces on seperate line (Allman)

function bar($baz)
{
    // ...
}

Method structure opening braces on same line as declaration (OTBS)

function bar($baz) {
    // ...
}

Blank line after <?php opening token

Blank line after <?php opening token

<?php

    // The line above this comment is empty
    // ...

No blank line after <?php opening token

<?php
    // The line above this comment is used
    // ...

Indentation (general)

2 Spaces for Indentation

class Foo {
  function bar($baz) {
    // uses two spaces for indentation
  }
}

4 Spaces for Indentation

class Foo {
    function bar($baz) {
        // uses four spaces for indentation
    }
}

Tabs for Indentation

class Foo {
    function bar($baz) {
        // uses one tab for indentation
    }
}

Indentation (switch -> case)

Don`t indent 'case' from 'switch'

switch($baz){
case 'bar':
// Regardless of where the `break` is
}

Indent 'case' one level from 'switch'

switch($baz){
    case 'bar':
    // Regardless of where the `break` is
}

Indent 'case' two levels from 'switch'

switch($baz){
        case 'bar':
        // Regardless of where the `break` is
}

Indentation (switch -> break)

Don`t indent 'break' from 'switch'

switch($baz){
// Regardless of where the `case` is
break;
}

Indent 'break' one level from 'switch'

switch($baz){
    // Regardless of where the `case` is
    break;
}

Indent 'break' two levels from 'switch'

switch($baz){
        // Regardless of where the `case` is
        break;
}

Line Endings

Mac Style Line Ending (CR)

echo 'foo';
// ...

Windows Style Line Ending (CRLF)

echo 'foo';
// ...

UNIX Style Line Ending (LF)

echo 'foo';
// ...

Space Around Control Structure Evaluation Block

Space around control structure Evaluation block

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

No space around control structure Evaluation block

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

Space Inside Control Structure Evaluation Block

Space inside control structure Evaluation block

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

No space inside control structure Evaluation block

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

Space Around Method Declaration Param Block

Space around parameter declaration block

function bar ($baz) {
    // ...
}

No space around parameter declaration block

function bar($baz){
    // ...
}

Space Inside Method Declaration Param Block

Space inside parameter declaration block

function bar( $baz ){
    // ...
}

No space inside parameter declaration block

function bar($baz){
    // ...
}

Naming Convention

Class Names

Class Name in camelCase

class fooBarBaz {
    // ...
}

Class Name in PascalCase

class FooBarBaz {
    // ...
}

Class Name in CAPS_SNAKE_CASE

class FOO_BAR_BAZ {
    // ...
}

Class Name in Snake_Pascal_Case

class Foo_Bar_Baz {
    // ...
}

Class Name in snake_case

class foo_bar_baz {
    // ...
}

Class Snake_first_letter_uppercase

class Foo_bar_baz {
    // ...
}

Class Constant Names

Class Constant Name in camelCase

class Foo {
    const barBaz = 0;
}

Class Constant Name in PascalCase

class Foo {
    const BarBaz = 0;
}

Class Constant Name in CAPS_SNAKE_CASE

class Foo {
    const BAR_BAZ = 0;
}

Class Constant Name in Snake_Pascal_Case

class Foo {
    const Bar_Baz = 0;
}

Class Constant Name in snake_case

class Foo {
    const bar_baz = 0;
}

Class Method Names

Class Method Name in camelCase

class Foo {
    public function barBaz(){
        // ...
    }
}

Class Method Name in PascalCase

class Foo {
    public function BarBaz(){
        // ...
    }
}

Class Method Name in CAPS_SNAKE_CASE

class Foo {
    public function BAR_BAZ(){
        // ...
    }
}

Class Method Name in Snake_Pascal_Case

class Foo {
    public function Bar_Baz(){
        // ...
    }
}

Class Method Name in snake_case

class Foo {
    public function bar_baz(){
        // ...
    }
}

Class Variable Names

Class Variable Name in camelCase

class Foo {
    protected $barBaz;
}

Class Variable Name in PascalCase

class Foo {
    protected $BarBaz;
}

Class Variable Name in CAPS_SNAKE_CASE

class Foo {
    protected $BAR_BAZ;
}

Class Variable Name in Snake_Pascal_Case

class Foo {
    protected $Bar_Baz;
}

Class Variable Name in snake_case

class Foo {
    protected $bar_baz;
}

Constant Names

Constant Name in camelCase

define('barBaz', 0);

Constant Name in PascalCase

define('BarBaz', 0);

Constant Name in CAPS_SNAKE_CASE

define('BAR_BAZ', 0);

Constant Name in Snake_Pascal_Case

define('Bar_Baz', 0);

Constant Name in snake_case

define('bar_baz', 0);

Function Names

Function Name in camelCase

function barBaz(){
    // ...
}

Function Name in PascalCase

function BarBaz(){
    // ...
}

Function Name in CAPS_SNAKE_CASE

function BAR_BAZ(){
    // ...
}

Function Name in Snake_Pascal_Case

function Bar_Baz(){
    // ...
}

Function Name in snake_case

function bar_baz(){
    // ...
}

Namespace Usage

Use Namespace

namespace Vendor\Package {
    class Foo {
        // ...
    }
}

Prefix Class Name instead of using Namespace

class Vendor_Package_Foo {
    // ...
}

PHP Constants Casing

PHP Constants LowerCase

$baz = true;
$baz = false;
$baz = null;

PHP Constants UpperCase

$baz = TRUE;
$baz = FALSE;
$baz = NULL;

PHP Keyword Casing

PHP Keywords LowerCase

try {
    if(){
        switch(){
            // ...
        }
    }
} catch (){
    // ...
}

PHP Keywords UpperCase

TRY {
    IF(){
        SWITCH(){
            // ...
        }
    }
} CATCH (){
    // ...
}

Other

Method Declare Order

static declared after visibility

class Foo
{
    public static function bar($baz) 
    {
        // ...
    }
}

static declared before visibility

class Foo
{
    static public function bar($baz) 
    {
        // ...
    }
}

abstract (or final) declared after visibility

class Foo
{
    public abstract function bar($baz);
    // ...
}

abstract (or final) declared before visibility

class Foo
{
    abstract public function bar($baz);
    // ...
}

Dockblocks

Docblocks manditory

/**
 * The Foo Class
 *
 * Takes care of all of the foos
 */
class Foo {
    /**
     * Bar a given Baz
     * 
     * @param $baz
     * 
     * @return bool
     */
    function bar($baz) {
        // ...
    }
}

Docblocks optional

class Foo {
    function bar($baz) {
        // ...
    }
}

Closing Tags

Closing tag ?> allowed or manditory

<?php
    // ...
?>

Closing tag ?> not allowed

<?php
    // ...
#EOF

Short Tags (general)

Short tag '<?' allowed

<p>
    <? echo $baz ?>
</p>

Short tag '<?' not allowed

<p>
    <?php echo $baz ?>
</p>

Short Tags (echo)

Short echo tag '<?=' allowed

<p>
    <?= $baz ?>
<p>

Short echo tag '<?=' not allowed

<p>
    <? echo $baz ?>
</p>

Always use control braces

Control braces mandatory

if($baz) {
    // ..
} else {
    // ..
}    

Control braces optional

if($baz)
    // ..
else
    // ..

Castaways and Cutouts

Linelength

Limit on 80 characters

// Break before hitting the 80 character line
//----------------------------------40-↓----------------------------------[80]-↓-----------------------------------120-↓-----------------------------------160-↓-----------------------------------200-↓-----------------------------------[∞]-→
$iterator = new RecursiveDirectoryIterator(
      $folder, FilesystemIterator::CURRENT_AS_FILEINFO 
    | FilesystemIterator::KEY_AS_PATHNAME 
    | FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS 
    | FilesystemIterator::UNIX_PATHS
);

Limit on 100 characters

// Break before hitting the 100 character line
//----------------------------------40-↓------------------------------------80-↓-------------[100]-↓---------------120-↓-----------------------------------160-↓-----------------------------------200-↓-----------------------------------[∞]-→
$iterator = new RecursiveDirectoryIterator(
      $folder, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_PATHNAME 
    | FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS 
    | FilesystemIterator::UNIX_PATHS
);

Limit on 120 characters

// Break before hitting the 120 character line
//----------------------------------40-↓------------------------------------80-↓---------------------------------[120]-↓-----------------------------------160-↓-----------------------------------200-↓-----------------------------------[∞]-→
$iterator = new RecursiveDirectoryIterator(
      $folder, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_PATHNAME 
    | FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS
);

No limit on line length

// I Break for no-one!
//----------------------------------40-↓------------------------------------80-↓-----------------------------------120-↓-----------------------------------160-↓-----------------------------------200-↓-----------------------------------[∞]-→
$iterator = new RecursiveDirectoryIterator($folder, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::FOLLOW_SYMLINKS | FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS);

Operators and assignment (Yoda Conditions/Left Side Comparison)

Normal comparison

if($baz === 'baz'){
    // ...
}

Yoda Condition/Left Side Comparison

if('baz' === $baz){
    // ...
}

Inter-line alignment (Vertical Lining Up Values)

Non-Aligned Values

$baz = 'baz';
$quux = 'qux';
$foozle = 'foo';

Aligned Values

$baz    = 'baz';
$quux   = 'qux';
$foozle = 'foo';

Comments and documentation blocks

Perl Style Comments

# This is a comment

C++ Style Comments

// This is a comment

C Style Comments

/* This is a comment */

Usage of underscore '_' for private/protected properties

Does not use underscore '_' for private/protected properties

class Foo {
    protected function bar($baz) {
        // ...
    }
}

Uses underscore '_' for private/protected properties

class Foo {
    protected function _bar($baz) {
        // ...
    }
}

The following list contains all of the conventions I can think of to include in the convention list. It is based on a comparison of various conventions as dictated by various more well-know projects.

Some of these may be dropped under influence of comments or lack of good examples.

Whitespace

  • File Encoding
  • Brace Placement (Class/Control Structures/Methods)
  • Blank line after <?php opening token
  • Indentation (general/switch)
  • Line Endings
  • Space (Control Structure Brackets/Around Param Block/Method Declaration Inside Param Block)

Naming Convention

  • Class Names
  • Class Constant Names
  • Class Method Names
  • Class Variable Names
  • Constant Names
  • Function Names
  • Namespace Usage
  • PHP Constants Casing
  • PHP Keyword Casing

Other

  • Method Declare Order
  • Dockblocks
  • Closing Tags
  • Short Tags (general/echo)
  • Always use Control braces

Castaways and Cutouts

There are several things mentioned that I don't think fall under "code style clash" but rather good/bad practices. I don't think these need to be included. Also, various things might be too tricky to measure and should be left out because of that.

  • Class name prefixes and suffixes : In lue of using proper namespace features (older) code often falls back to using snake case and prefixes for vendors, etc. I think this will be reflected in the naming convention checks and doesn't warrent this level of detail.
  • Comments and documentation blocks : Various styles could be easy to check, like //, # and /**/. However, there would have to be a check to take docblocks into account /** */, otherwise that would throw everyting of in favour of /**/.
  • Conventions for file names : There are various conventions on how to name a file depending on whether it contains a class, config or other forms of content but I don't think this could be reliably measured.
  • Declaration of global variables and global constants : Doesn't seem worth the effort to gauge this.
  • Declaration of Functions : Check whether people only declare functions as class methods or as procedural functions. Do we care? I think this is more context dependant than coding or convention style.
  • Error Level : This one is alsorather ambiguous as often the error level is declared outside of the project code. There could be a check for usage of error_reporting but then integers could be used instead of constants, making the whole thing more tiresome than seems worth the effort.
  • Operators and assignment (Yoda Conditions/Left Side Comparison) : This would be hard to reliably check for without doing extra code analysis (scan for the dollar sign $). Could be worthwhile to find out. Not sure.
  • Inter-line alignment (Vertical Lining Up Values) : Why bother? People hardly seem to notice the difference as is.
  • Line Length (hard limit/soft Limit) : I have a feeling this would rather hard to check for, since normative lines of code will be less than 80 characters long anyway.
  • Usage of include_once versus require_once? : Doesn't seem worth the effort and can very likely be context dependant.
  • Usage of underscore '_' for private/protected properties : This is a bit of PHP4 legacy. The PSR explicitly says "do not use", some others explicitly say yes. Could be interesting. Not sure.

EOF

Popular Coding Convention in PHP on Github

For everyone's entertainment I though it might be nice to get PHP added to the Popular Coding Convention on Github site.

A request had already been made so I decided to pick up the gauntlet.

My plan of attack is as follows:

  1. make a list of all the coding style conventions the different PHP factions tend to squabble or complain about
  2. Add code examples explaining the different possible variations
  3. Solicit feedback from a few more renowned (or opinionated) community members with the aid of semaphores, tin-can-phone or smoke signals. Or twitter if my wife still won't let me play with matches.
  4. Edit the text to reflect various contributions
  5. ...
  6. Profit!

[UPDATE]:

After creating a list based on the PSR2 I began to get this feeling of uncertainty that it might be incomplete. It was also unclear from the PSR2 alone where conflicts would arise with other conventions. So rather than to just guess and hope for the best I decided to take several coding standards and map their conventions and that way I would have an actual basis in fact for my set of possible convention conflicts. I got a bit too obsessed with the detail for a while there, causing some delay. Various yaks needed shaving an I changed jobs during that period as well, but I got my act together in the end.

Step 1 - Compose as list

The best place to go to find out which coding style clashes we as a community have seemed to me to be the FIG site. Based on the PSR-1 and PSR-2 I came up with the list below.

Step 2 - Add examples

Several weekendends later, my list sort of turned into a side project in it's own right but putting it all back together and drawing it back into the scope of this project, it looks complete.

Step 3 - Feedback

The first people that come to mind, other than my co-hooligans are @skoop, @jaytaph, @mvriel, @rdohms, @dr4goonis and maybe @philsturgeon.

Step 4 - Final Edits

From the feedback I received it would seem nothing is missing, so all is good!

Step 5 - ...

Ellipsis!

Step 6 - Profit!

Or just have some more fun, maybe? In either case, the information here seems complete and is ready for use.