bit3/php-coding-standard

This package is abandoned and no longer maintained. The author suggests using the contao-community-alliance/coding-standard package instead.

bit3 PHP coding standards

Installs: 1 716

Dependents: 27

Suggesters: 0

Security: 0

Stars: 2

Watchers: 4

Forks: 0

Type:coding-standard

2.4 2013-11-29 04:08 UTC

This package is not auto-updated.

Last update: 2022-02-01 12:26:15 UTC


README

These are our coding standards.

This coding standard based on the great TYPO3 coding standard, see http://forge.typo3.org/projects/team-php_codesniffer/wiki/Using_the_TYPO3_Coding_Standard

Philosophy

Our philosophy: Write fast readable and comprehensible code. Don't be shy to write more lines, if it makes each line more atomic.

What is the benefit of atomic lines? When each line is full atomic (only contains one operation), the order of lines reflect the execution order of the commands.

When you have a complex line like this:

$variable = ($foo != $bar && count($zap) || $dig) ? $this->func($zap, $foo, $bar) : $this->other(count($zap))->chain($foo, $bar);

How is the order of execution? What do this code? You can understand if you analyse the line, but its hard to do. Simplified this is the execution order of the operations:

evaluate $foo != $bar
execute count($zap)
evaluate count($zap)
evaluate .. && ..
evaluate $zip
evaluate .. || ..
if true
  execute $this->func($zap, $foo, $bar)
else
  execute count($zap)
  evaluate count($zap)
  execute $this->other(count($zap))
  execute $..->chain($foo, $bar)
assign $variable

If you want to understand what this code do, you have to understand the execution order of the operations and the meaning of each operation. If you write this in a more atomic style, you make it easier to understand, for others and yourself if you nod touch the code a long time!

Compare against this, it is exactly the same code:

if (
	$foo != $bar && count($zap) ||
	$dig
) {
	$variable = $this->func($zap, $foo, $bar);
}
else {
	$variable = $this->other(count($zap))->chain($foo, $bar);
}

As you can see, this snippet more reflect the execution order and it is much easier to understand what it do.

Usage

Install the coding standards via composer:

"require-dev":{
	"bit3/php-coding-standard":"@dev"
}

After updating dependencies, copy the example ant build file from vendor/bit3/php-coding-standard/example/build.xml into your project. If your sources are not in src/, change the path to your sources in the build file.

Hint: If you not use phpunit, remove the phpunit target from build file.

You can run the tests by invoke ant phpmd and ant phpcs. Running ant or ant test will run all test targets.

Hint: To run all testes, even if one fail, use ant -keep-going.

Definitions

  • long line means a line that is longer than 60 characters.
  • No line should be longer than 100 characters.
  • No line must be longer than 120 characters.

Files

No file must contain more than one class, interface or function. The file name must the same (including case) as the class, interface or function named defined in it. Without any prefix (e.g. class.) or suffix (e.g. .inc), expect the the file type extension .php.

Runner scripts, should contain a runner class, containing a run method.

Example index.php:

<?php

require_once('autoload.php');

class index
{
	public function run()
	{
		// runtime code
	}
}

$index = new index();
$index->run();

Hint: Runner classes must not be in pascal-case, but must match the file name.

Second example ajax.php

<?php

class ajax
{
	public function run()
	{
		// runtime code
	}
}

$ajax = new ajax();
$ajax->run();

Whitespaces

Do not use SPACE for indention. Use TAB.

Add spaces to split operators:

  • assignment: $variable = 'value'
  • parameters: func($a, $b, $c)
  • arrays: array('foo' => 'bar', 'bar' => 'foo')
  • comments: // comment or * multiline comment

Class and function declaration

Place opening brace { on new line for all non-control-structures like class or function declaration. Place extends and implements on new line and indent one time.

class Foo
	extends Bar
	implements Zap
{
	public function func()
	{
		...
	}
}
function func()
{
	...
}

Don't add a space before opening bracked ( in function declarations or calls.

Naming

Use pascal-case class names.

// bad
class foo_bar {
}

// good
class FooBar {
}

Use camel-case method names.

// bad
function foo_bar() {
}

// good
function fooBar() {
}

Control structures

Place opening brace { on same line for all control-structures. Add newline after closing brace }, even the control-structure continues.

if (...) {
	...
}
else if (...) {
	...
}
else {
	...
}
for (...) {
	...
}
foreach (...) {
	...
}
while (...) {
	...
}
do {
	...
}
while (...);

Why putting the else on a new line? It's simple, first it is the beginning of a new block. Second it is easier to make comments that describe the conditions.

// describe if condition
if (...) {
	...
}
// describe else if condition
else if (...) {
	...
}
// describe else condition
else {
	...
}

Long and multiline conditions

If control-structure condition gets to long, place closing bracket and opening brace ) { in a separate line and place condition in separate line.

if (
	... very long ...
	... multiline ...
) {
	...
}
else if (
	... very long ...
	... multiline ...
) {
	...
}
else {
	...
}
for (
	... very long ...
	... multiline ...
) {
	...
}
foreach (
	... very long ...
	... multiline ...
) {
	...
}
while (
	... very long ...
	... multiline ...
) {
	...
}
do {
	...
}
while (
	... very long ...
	... multiline ...
);

Don't forget the whitespace before opening bracket (.

Ternary operator

When using ternary operator, you should put then and else part in separate lines and indent one time if line gets longer.

// good
$variable = $if ? $then : $else;

// good
$variable = $if ? $this->then() : $this->else();

// bad
$variableObjectname = $someLongVariable != $otherLongVariable ? $veryLongVariableName : $anotherVeryLongVariableName;

// good
$variableObjectname = $someLongVariable != $otherLongVariable
	? $veryLongVariableName
	: $anotherVeryLongVariableName;

Ternary operator should only be used for simple left/right decisions. Do not use in combination with complex conditions or logic.

// bad, use formated if-statement instead
$variable = $firstVariable != $secondVariable && someCheckFunction($variableName) || anotherCheckFunction($thirdVariable)
	? $this->someComplexFunction($firstVariable, $secondVariable, $thirdVariable)
	: 'some string prefix ' . substr($this->otherComplexFunction($variablename), 0, strlen($thirdVariable)) . ' some string suffix';

// good
$variable = $firstVariable != $secondVariable ? $this->then() : $this->else();

// good
$variable = someCheckFunction($variableName) ? $then : $else;

Function/Method calls

In function/method calls use space to split parameters, but do not add space before opening bracket (.

// bad
func ('a','b','c');

// good
func('a', 'b', 'c');

When parameter list gets long, make it multiline and put every parameter on a singleline. Also put the closing bracket ) on a singleline.

// bad
func ('short', 'short',
	'very long param');

// good
func(
	'short',
	'short',
	'very long param'
);

When chain method calls, put each method call in separate line if it make sense or the line gets to long.

// bad
$database->prepare('SELECT a,long,list,of,fields FROM some_table WHERE some_complex_and_long_where')->limit(100)->offset(50)->execute();

// a little bit better
$database->prepare('SELECT a,long,list,of,fields FROM some_table WHERE some_complex_and_long_where')
	->limit(100)->offset(50)->execute();

// good
$database
	->prepare('SELECT a,long,list,of,fields FROM some_table WHERE some_complex_and_long_where')
	->limit(100)
	->offset(50)
	->execute();

Variables

Initialisation

Make complex array initialisations multiline and put every element in single line.

$array = array(
	'item1',
	'item2',
	'item3',
);
$array = array(
	'index1' => 'item1',
	'index2' => 'item2',
	'index3' => 'item3',
);

Naming

Use camel-case variable names. Use significant variable names instead type prefix.

// bad
$intUser = 1;

// good
$userId = 1;
// bad
$objUser = ...some object...;

// good
$user = ...some object...;
// bad
$arrUsers = array(1, 2, 3);

// good
$userIds = array(1, 2, 3);
// bad
$arrUsers = array(...object..., ...object..., ...object...);

// good
$users = array(...object..., ...object..., ...object...);

Logic

Keep every line as simple as possible, do not combine to many operations in one line. Use readable control structures if needed, even you write a lot more lines!

// bad
$variable = ($foo != $bar && count($zap) || $dig) ? $this->func($zap, $foo, $bar) : $this->other(count($zap))->chain($foo, $bar);

// good
$n = count($zap);
if (
	$foo != $bar && $n ||
	$dig
) {
	$variable = $this->func($zap, $foo, $bar);
}
else {
	$variable = $this->other($n)->chain($foo, $bar);
}

Don't use logic in function call parameters.

// bad
func(
	$if
		? $then
		: $else,
	'foo',
	other('bar')
);

// good
$param = $if
	? $then
	: $else;
$other = other('bar');
func(
	$param,
	'foo',
	$other
);

Use function or method chaining with caution, but keep it as simple as possible.

// avoid illogical chaining
// $this->func, strlen and file_get_contents does not logical belongs to each other
$this->func(strlen(file_get_contents('/some/file')));

// better
$content = file_get_contents('/some/file');
$this->func(strlen($content));

// best
$content = file_get_contents('/some/file');
$length  = strlen($content);
$this->func($length);
// be gentle with logical chaining
// the array_* functions are logical belongs to each other,
// but its hard to understand this at a glance
$result = array_values(array_filter(array_map('trim', $array)));

// better
$result = array_values(
	array_filter(
		array_map(
			'trim',
			 $array
		 )
	)
);

// best, keep it simple, fast readable and more comprehensible - and it is short :-)
$result = array_map('trim', $array);
$result = array_filter($result);
$result = array_values($result);