# Conventions and Coding Style

It is encouraged that you follow Koseven's coding style. This makes code more readable and allows for easier code sharing and contributing. 

## Class Names and File Location

Class names in Koseven follow a strict convention to facilitate [autoloading](autoloading). Class names should have uppercase first letters with underscores to separate words. Underscores are significant as they directly reflect the file location in the filesystem.

The following conventions apply:

1. CamelCased class names should be used when it is undesirable to create a new directory level.
2. All class file names and directory names must match the case of the class as per [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md).
3. All classes should be in the `classes` directory. This may be at any level in the [cascading filesystem](files).

### Examples  {#class-name-examples}

Remember that in a class, an underscore means a new directory. Consider the following examples:

Class Name            | File Path
----------------------|-------------------------------
Controller_Template   | classes/Controller/Template.php
Model_User            | classes/Model/User.php
Model_BlogPost        | classes/Model/BlogPost.php
Database              | classes/Database.php
Database_Query        | classes/Database/Query.php
Form                  | classes/Form.php

## Coding Standards

In order to produce highly consistent source code, we ask that everyone follow the coding standards as closely as possible.

### Brackets

Please use [BSD/Allman Style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracketing.  

#### Curly Brackets

Curly brackets are placed on their own line, indented to the same level as the control statement.

	// Correct
	if ($a === $b)
	{
		...
	}
	else
	{
		...
	}

	// Incorrect
	if ($a === $b) {
		...
	} else {
		...
	}

#### Class Brackets

The only exception to the curly bracket rule is, the opening bracket of a class goes on the same line.

	// Correct
	class Foo {

	// Incorrect
	class Foo
	{

#### Empty Brackets

Don't put any characters inside empty brackets.

	// Correct
	class Foo {}

	// Incorrect
	class Foo { }

#### Array Brackets

Arrays may be single line or multi-line.

	['a' => 'b', 'c' => 'd']
	
	[
		'a' => 'b', 
		'c' => 'd',
	]

##### Closing parenthesis

###### Single Dimension

The closing parenthesis of a multi-line single dimension array is placed on its own line, indented to the same level as the assignment or statement.

	// Correct
	$array = [
		...
	]

	// Incorrect
	$array = [
		...
		]

###### Multidimensional

The nested array is indented one tab to the right, following the single dimension rules.

	// Correct
	[
		'arr' => [
			...
		],
		'arr' => [
			...
		],
	]
	
	[
		'arr' => [...],
		'arr' => [...],
	]
	
##### Arrays as Function Arguments


	// Correct
	do([
		...
	])
	
	// Incorrect
	do([
		...
		])

As noted at the start of the array bracket section, single line syntax is also valid.

	// Correct
	do([...])
	
	// Alternative for wrapping long lines
	do($bar, 'this is a very long line',
		[...]);

### Naming Conventions

Koseven uses under_score naming, not camelCase naming.

#### Classes

	// Controller class, uses Controller_ prefix
	class Controller_Apple extends Controller {

	// Model class, uses Model_ prefix
	class Model_Cheese extends Model {

	// Regular class
	class Peanut {

When creating an instance of a class, don't use parentheses if you're not passing something on to the constructor:

	// Correct:
	$db = new Database;

	// Incorrect:
	$db = new Database();

#### Functions and Methods

Functions should be all lowercase, and use under_scores to separate words:

	function drink_beverage($beverage)
	{

#### Variables

All variables should be lowercase and use under_score, not camelCase:

	// Correct:
	$foo = 'bar';
	$long_example = 'uses underscores';

	// Incorrect:
	$weDontWantThis = 'understood?';

### Indentation

You must use tabs to indent your code. Using spaces for tabbing is strictly forbidden.

Vertical spacing (for multi-line) is done with spaces. Tabs are not good for vertical alignment because different people have different tab widths.

	$text = 'this is a long text block that is wrapped. Normally, we aim for '
		  .'wrapping at 80 chars. Vertical alignment is very important for '
		  .'code readability. Remember that all indentation is done with tabs,'
		  .'but vertical alignment should be completed with spaces, after '
		  .'indenting with tabs.';

### String Concatenation

Do not put spaces around the concatenation operator:

	// Correct:
	$str = 'one'.$var.'two';

	// Incorrect:
	$str = 'one'. $var .'two';
	$str = 'one' . $var . 'two';

### Single Line Statements

Single-line IF statements should only be used when breaking normal execution (e.g. return or continue):

	// Acceptable:
	if ($foo == $bar)
		return $foo;

	if ($foo == $bar)
		continue;

	if ($foo == $bar)
		break;

	if ($foo == $bar)
		throw new Exception('You screwed up!');

	// Not acceptable:
	if ($baz == $bun)
		$baz = $bar + 2;

### Comparison Operations

Please use || and && for comparison:

	// Correct:
	if (($foo && $bar) || ($b && $c))

	// Incorrect:
	if (($foo AND $bar) OR ($b AND $c))
	
Please use elseif, not else if:

	// Correct:
	elseif ($bar)

	// Incorrect:
	else if($bar)

### Switch Structures

Each case, break and default should be on a separate line. The block inside a case or default must be indented by 1 tab.

	switch ($var)
	{
		case 'bar':
		case 'foo':
			echo 'hello';
		break;
		case 1:
			echo 'one';
		break;
		default:
			echo 'bye';
		break;
	}

### Parentheses

There should be one space after statement name, followed by a parenthesis. The ! (bang) character must have a space on either side to ensure maximum readability. Except in the case of a bang or type casting, there should be no whitespace after an opening parenthesis or before a closing parenthesis.

	// Correct:
	if ($foo == $bar)
	if ( ! $foo)

	// Incorrect:
	if($foo == $bar)
	if(!$foo)
	if ((int) $foo)
	if ( $foo == $bar )
	if (! $foo)

### Ternaries

All ternary operations should follow a standard format. Use parentheses around expressions only, not around just variables.

	$foo = ($bar == $foo) ? $foo : $bar;
	$foo = $bar ? $foo : $bar;

All comparisons and operations must be done inside of a parentheses group:

	$foo = ($bar > 5) ? ($bar + $foo) : strlen($bar);

When separating complex ternaries (ternaries where the first part goes beyond ~80 chars) into multiple lines, spaces should be used to line up operators, which should be at the front of the successive lines:

	$foo = ($bar == $foo)
		 ? $foo
		 : $bar;

### Type Casting

Type casting should be done with spaces on each side of the cast:

	// Correct:
	$foo = (string) $bar;
	if ( (string) $bar)

	// Incorrect:
	$foo = (string)$bar;

When possible, please use type casting instead of ternary operations:

	// Correct:
	$foo = (bool) $bar;

	// Incorrect:
	$foo = ($bar == TRUE) ? TRUE : FALSE;

When casting type to integer or boolean, use the short format:

	// Correct:
	$foo = (int) $bar;
	$foo = (bool) $bar;

	// Incorrect:
	$foo = (integer) $bar;
	$foo = (boolean) $bar;

### Constants

Always use uppercase for constants:

	// Correct:
	define('MY_CONSTANT', 'my_value');
	$a = TRUE;
	$b = NULL;

	// Incorrect:
	define('MyConstant', 'my_value');
	$a = True;
	$b = null;

Place constant comparisons at the end of tests:

	// Correct:
	if ($foo !== FALSE)

	// Incorrect:
	if (FALSE !== $foo)

This is a slightly controversial choice, so I will explain the reasoning. If we were to write the previous example in plain English, the correct example would read:

	if variable $foo is not exactly FALSE

And the incorrect example would read:

	if FALSE is not exactly variable $foo

Since we are reading left to right, it simply doesn't make sense to put the constant first.

### Comments

#### One-line Comments

Use //, preferably above the line of code you're commenting on. Leave a space after it and start with a capital. Never use #.

	// Correct

	//Incorrect
	// incorrect
	# Incorrect

### Regular Expressions

When coding regular expressions please use PCRE rather than the POSIX flavor. PCRE is considered more powerful and faster.

	// Correct:
	if (preg_match('/abc/i', $str))

	// Incorrect:
	if (eregi('abc', $str))

Use single quotes around your regular expressions rather than double quotes. Single-quoted strings are more convenient because of their simplicity. Unlike double-quoted strings they don't support variable interpolation nor integrated backslash sequences like \n or \t, etc.

	// Correct:
	preg_match('/abc/', $str);

	// Incorrect:
	preg_match("/abc/", $str);

When performing a regular expression search and replace, please use the $n notation for backreferences. This is preferred over \\n.

	// Correct:
	preg_replace('/(\d+) dollar/', '$1 euro', $str);

	// Incorrect:
	preg_replace('/(\d+) dollar/', '\\1 euro', $str);

Finally, please note that the $ character for matching the position at the end of the line allows for a following newline character. Use the D modifier to fix this if needed. [More info](http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html).

	$str = "email@example.com\n";

	preg_match('/^.+@.+$/', $str);  // TRUE
	preg_match('/^.+@.+$/D', $str); // FALSE
