"Coding principles" are general rules on how to write and format PHP-code. These rules are meant to help, to keep your source code easy to read and understand.
If several authors are working together on the same source code, it is quite common, that each author may have it's own idea on how clean code should look like. There are dozens of possibilities to express the same thing with PHP. To ensure the source code remains well readable in the long term, it is necessary that all authors agree on a common standard on how to write statements.
The "Coding principles" stated here provide such a definition. These rules are not obligating, however, I would like to recommend them to you.
The source code should be indented with 4 blanks. Do not use tabulators, because these can be viewed differently on different systems.
For comments use exclusively the syntax /* comment */. This has a deeper meaning! Later, when you write or use scripts, that analyse or automatically document your source code, this will make your task a lot easier. Unlike the syntax // comment or # comment, you have a fixed start and end for each comment, that you can rely on. Lines of comments can be fetched easily with simple regular expressions, saving you much effort when creating these scripts.
Here is a example.
<?php
$output = array();
/* iterate through input */
foreach ($input as $key => $element)
{
$element = strip_tags( (string) $element);
if (preg_match("/\//", $key)) {
$key = preg_replace("/\//", ".", $key);
Hashtable::set($output, $key, $element);
} else {
$output[$key] = $element;
}
} /* end foreach */
?>
In PHP has no variable declaration in the sense of other languages. Nevertheless variables have a certain life span. Before and after a variable's life span it does not exist, what means no value is assigned.
The reason for many errors in PHP is, that programmers assume a variable to be unused, of a certain type, or that is no longer used after a certain code line. However PHP does NOT ensure that and also will not warn you if you are wrong, unless you "please" it to do so. This is exactly what you should do!
If you do it, PHP will warn you, if you use a variable outside it's life span and by doing so will possibly save you many hours of debugging!
Variables should be named in CamelCase - for example, $debugSourcePath instead of $debug_source_path. The first letter should always be written small - in difference to class names. There (and only there) the first letter should be large. This definition for the way of writing is similar to that in many other languages like Java.
<?php
/* Start of life span */
/* The following line will warn you if the variable already exists */
assert('!isset($variable); // Cannot redeclare $variable');
/* always initialize variables before use */
$variable = 0;
/* ... additional statements ... */
/* If a variable is no longer needed it should always explicitly be unset */
unset($variable);
/* End of life span */
?>
When working with if and else, please always use brackets { } for each block. While PHP permits to spare these brackets, if a block consists of only one statement, this style of coding is error-prone, since you may always come to the point where you decide to add another line of code and in this situation it is easy to oversee the missing brackets.
If an If-block is very long (more than 10 lines), you should add a comment /* end if */ at the closing bracket for better readability. For long code blocks this helps to identify what statement a bracket belongs to.
<?php
if ($test1) {
/* ... */
} elseif ($test2) {
/* ... */
} else {
/* ... */
} /* end if */
?>
When using Switch-statements mind the text indentation and line breaks, which serve readability.
Avoid using "fall trough", for this may lead to code which is difficult to read. If you somehow cannot avoid it, you should mark this special case with the comment /* fall through */ instead of the Break-statement for documentation.
The Default-case should always be included. This enhances the clarity of your code.
If two different cases use the same code, this can be expressed by writing case 1: case 2: ... break;. This is a useful abbreviation and you are recommended to use it, where you see fit.
<?php
switch ($variable)
{
case 1:
/* ... */
break;
case 2: case 3:
/* ... */
break;
case 4:
/* ... */
break;
case 5:
/* ... */
break;
case 6:
/* ... */
/* fall through */
default:
/* ... */
break;
} /* end switch */
?>
Again mind the line breaks for better readability.
PHP has a rather uncommon "feature". The life span of a block / loop -variable does NOT end, as in other languages, when exiting the block / loop, but will continue to have it's last assigned value. This also means that loop variables in PHP may overwrite the value of another, already existing variable. PHP will not warn you on this issue. To address this behavior, and the potential risk, which is associated´with it, you should treat the begin of any For- or ForEach-loop like a variable declaration and check whether any used loop variables already exist. When exiting a loop, you should always explicitly unset variables to avoid side effects.
Note that a ForEach statement necessarily expects an array to work on. Before entering the loop check the type of the input variable by using the function is_array () and add appropriate error handling if the variable has not the expected type.
For While-loops ensure that exit points, introduced by Break- or Continue-statements, are always sufficiently documented.
Take a look at the following examples:
<?php
/* Example: FOR-loop */
assert('!isset($i); // Cannot redeclare $i');
for ($i = 0; $i < sizeOf($input); $i++)
{
/* ... */
} /* end for */
unset($i);
/* Example: FOREACH-loop */
assert('!isset($key); // Cannot redeclare $key');
assert('!isset($element); // Cannot redeclare $element');
foreach ($input as $key => $element)
{
/* ... */
} /* end foreach */
unset($key);
unset($element);
/* Example: WHILE-loop */
while ($test)
{
/* ... */
} /* end while */
?>
For the names of classes and functions be advised to uniformly use CamelCase. For function names, the first letter is always small.. For class names the first letter is always capitalized. This rule is similar to Java and other C-type languages.
In PHP it is common that the names of private functions and methods start with an underscore to improve readability. If you decide to use this notation, please use it only for identification of private functions and methods.
To improve readability it is recommended, that the name of a function starts with a verb in imperative and a noun in singular, for example: "getBeer()" or "setContent()". If the return value is a list object or an array, use a noun in plural, for example: "getLines()".
Use PHPDoc comments (http://www.phpdoc.org/) for documentation of classes and functions. These should be mandatory. Make it a habit to always immediately document any new function you write, while the idea and details are still fresh in your memory. By writing documentation you are forced to review the content of your work and thus will recognize mistakes, false assumptions or defective pre-conditions earlier.
The documentation of a function should always contain: the input data the function expects (for example: "an integer between 0 and 5"), the purpose of the function - that is what this does. Moreover, the return values of the function (for example: "an integer between 1 and 6, or false, if an error occurs").
It is general practice to document source codes in English. If you are able to write your documentation in English, then do so.
If you want to use UML-style stereotypes, then write them in front of the name of the function or class and use parentheses, which is common for writing stereotypes.
It is common to keep variables "private" and the restrict all access to set - and get-functions. For example, access to a private variable "$foo" should be restricted to functions with the name "setFo ()" and "getFoo()". Note that the class variables must always be initialized - if necessary, initialize them with the constant "null"!
<?php
/**
* «Stereotype» name
*
* The purpose of this class is ...
*
* @access public
* @package package
* @subpackage subpackage
*/
class MyClass extends BaseClass
{
/**#@+
* @access private
*/
/** @var array */ private $var1 = array();
/** @var int */ private $var2 = 0;
/** @var View */ private $var3 = null;
/** @var array */ private $var4 = array();
/** @var array */ private $var5 = array();
/**#@-*/
/**
* «Stereotyp» Constructor
*
* This function accepts the following input ...
*
* This function does ...
*
* It returns the following values ...
*
* @param string $filename path to file.ext
*/
public function __construct ($filename)
{
/* ... */
}
/**
* «Stereotype» name
*
* This function accepts the following input ...
*
* This function does ...
*
* It returns the following values ...
*
* @access public
* @param string $id alphanumeric, unique identifier
* @return int
*/
public function getVar ($filename)
{
/* ... */
}
}
?>
Thomas Meyer, www.yanaframework.net