- b2evolution CMS User Manual
- Developer Reference
- Development
- Coding Standard Guidelines
Coding Standard Guidelines
PHP guidelines
Editor Settings
Tabs vs Spaces: In order to make this as simple as possible, we will be using tabs, not spaces. Feel free to set how many spaces your editor uses when it displays tabs, but make sure that when you save the file, it’s saving tabs and not spaces.
Note: Our preferred tab length is 3 but we only use them at the beginning of lines anyways, not for aligning comments at end of lines (use spaces there).
Line endings: Please make sure that your Git client correctly converts line endings to Unix format, especially if you are developing on Windows.
Where to put the braces
This one is a bit of a holy war, but we’re going to use a style that can be summed up in one sentence: Braces always go on their own line. The closing brace should also always be at the same column as the matching opening brace.
Examples:
if( condition )
{ // This is a good place for a comment!
while( condition2 )
{ // This is a good place for a comment!
...
}
}
else
{ // This is a good place for a comment!
...
}
for( $i = 0; $i < $size; $i++ )
{ // This is a good place for a comment!
...
}
while( condition )
{ // This is a good place for a comment!
...
}
function do_stuff()
{ // This is a good place for a comment!
...
}
Where to use spaces
Use spaces between tokens: this is another simple, easy step that helps keep code readable without much effort. Basically, write code as if it was English, with the exception of brackets.
- Whenever you write an assignment, expression, etc.. always leave one space between the tokens.
- Put spaces between variable names and operators.
- Don’t put spaces just before a comma or a semicolon.
- Don’t put spaces around the concatenation operator
.
.
This is best shown with a few examples.
// instead of:
$i=0;
// please write:
$i = 0;
// instead of:
if($i<7) ...
// please write:
if( $i < 7 ) ...
// instead of:
if ( ($i < 7)&&($j < 8) ) ...
// please write:
if( ($i < 7) && ($j < 8) ) ...
// instead of:
do_stuff($i,"foo",$b);
// please write:
do_stuff( $i, 'foo', $b );
// instead of:
for($i=0; $i<$size; $i++) ...
// please write:
for( $i = 0; $i < $size; $i++ ) ...
// instead of:
$i=($j < $size)?0:1;
// please write:
$i = ( $j < $size ) ? 0 : 1;
// instead of:
'Hello' . ' world!'
// please write:
'Hello'.' world!'
Operator precedence
Do you know the exact precedence of all the operators in PHP? Neither do I. Don’t guess. Always make it obvious by using brackets to force the precedence of an equation so you know what it does.
Examples:
/* what's the result? who knows? */
$bool = ($i < 7 && $j > 8 || $k == 4);
/* now you can be certain what I'm doing here. */
$bool = ( ($i < 7) && ( ($j > 8) || ($k == 4) ) )
Quoting strings
There are two different ways to quote strings in PHP - either with single quotes '
or with double quotes "
. The main difference is that the parser does variable replacements in double-quoted strings, but not in single quoted strings. Because of this, you should always use single quotes unless you specifically need variable interpolation to be done on that string. This way, we can save the parser the trouble of parsing a bunch of strings where no interpolation needs to be done. Also, if you are using a string variable as part of a function call, you do not need to enclose that variable in quotes. Again, this will just make unnecessary work for the parser.
Note, however, that nearly all of the escape sequences that exist for double-quoted strings will not work with single-quoted strings. Be careful, and feel free to break this guideline if it’s making your code harder to read.
Examples:
// Don't write:
$str = "This is a really long string with no variables for the parser to find.";
do_stuff("$str");
// Write this instead:
$str = 'This is a really long string with no variables for the parser to find.';
do_stuff( $str );
// Don't write:
echo "This is one line.\r\nThis is another.";
// Write this instead:
echo 'This is one line.'."\r\n".'This is another.'
// Don't write:
$str = 'Hello';
echo "Our \$str variable contains: [$str]";
// Write this instead:
$str = 'Hello';
echo 'Our $str variable contains: ['.$str.']';
Variable names, Member names, Class names
-
Remember this is PHP, not Microsoft Visual C++. There is actually little value in naming variables something like
strFullTitle
. Something likefull_title
is definitely enough and much easier to read! -
As an exception to the previous rule, we’ll preferably prefix private or protected member variables of a class with an underscore as in
_full_title
. This serves as an easy reminder that the variable is not designed to be called in any other ways as in$this->_full_title
. -
You will also see underscores (
_
) being used within file names. This shows that the php page is not to be accessed directly but instead is to an inclusion to another php page.require('_file.ext');
-
Class names should start with a capital, as in
Book
. -
Variable names should be all lowercase, as in
$title = 'A brand new day';
except when they are object references as in:$a_Book = & new Book( 'A brand new day' );
-
When naming object references, always end their name with the name of the class as in
$a_Book
or$another_Book
instead ofBook_to_read
for example. This allows to easily search & find all calls to a given method of a given class. You could for example easily search on this string:Book->get_title(
. -
If you are creating a variable to contain the value of a variable inside a class, we would name it like so
$Obj_var
, where "Obj" is the name of the class and "var" is the name of the variable, Eg:$Item_title = $Item->title; // not: $Items_title = $Item->title;
Translatable Strings / i18n / l10n
"Whenever" you add an user-interface string containing English words, enclose it in T_( )
to enable translation when users run b2evo in another language. T_('Hello!')
means "Translate the string ‘Hello!’ now".
Note: Don’t do this for debug or log messages. It would be too much work for the translators and the translations would probably not be helpful for the sys admins.
This is not a magical translation. It uses a dictionary of all strings and their translation into other languages. The process works like this:
- A parser extracts all strings found in the code, enclosed in
T_()
,TS_()
orNT_()
and generates a file of all strings to be translated. This is called a "POT file" for historical reasons. - Many translators translate many strings into their language. Here is more info about how translators work. This generates a "PO file" for each language.
- Each PO file is converted to a PHP array of all English => Localized strings. This is part of each language pack.
- When the code is executed, a call to
T_()
or toTS_()
looks up the string in the array and displays the result. The difference betweenT_()
andTS_()
is the escaping of special characters.TS_()
is useful for use in Javascript.
NT_()
on the contrary is a function that does nothing. NT_('Hello!)
means "No Translation of ‘Hello!’". So it will return the original English string in all cases. It is still useful because it allows extraction of the string by the parser. It allows to have deferred translation. Here is an example:
A very simple case is:
echo T_('Hello!');`
But you will get no translation if you try to use:
$a = 'Hello!';
echo T_($a);
The reason is that, here, the string ‘Hello!’ will never be extracted and included in the list of strings to be translated. So you would need to use:
$a = NT_('Hello!');
echo T_($a);
Likewise, the following is wrong:
$a = NT_('Hello!');
echo T_($a.' Welcome here!');
This will mess up the process of extracting the string. But you could use this for example:
$a = NT_('Hello!');
echo T_($a).' '.T('Welcome here!');
Note that each string should be a self contained sentence. Please NEVER assemble sentences like this:
$a = NT_('Hello');
echo T_($a).T(' and welcome here!');
This is WRONG because it’s very hard for translators to translate parts of a sentence and it may not work in all languages. The order of words may end up wrong in some languages.
Please also look at some examples in the code, especially sprintf()
examples. The marked strings will be automatically extracted for translation .
For %
signs in translatable strings: if you mean %
literally as opposed to %d
or %s
for example, you should escape the %
symbol with another %
preceding the first one. For example, if the original string is something like: % of active users
, it should be encoded like this: %% of active users
. Note: specifiers are the characters mentioned as parameters on this page: http://php.net/manual/en/function.sprintf.php.
IMPORTANT: Every time you add a string it adds tremendous work to translate it to all languages, so chose carefully. Any time you can re-use another string that already exists, do it! A very bad example is having T_('Note')
and T_('Note:')
and maybe even T_('Note!')
. In this case there should be only one string!
DO NOT include HTML code in the translatable strings! For example, the folling is very wrong:
T_('To do this action, <a href="http://..." class="btn">click here</a>')
A translator would have a 99% chance of creating a bug when trying to translate that. Instead use something like this:
sprintf( T_('To do this action, <a %s>click here</a>'), 'href="http://..." class="btn"' )
Miscellaneous
-
Do not use PHP short opening tags
<?
. Always use<?php
as some users run on hosts not supporting the short tags. -
Use require instead of include. Use require_once when including functions and global definitions.
-
Use Perl compatible regular expressions (
preg_ functions
) instead of POSIX. (better performance). -
Do not use the function mb_detect_encoding(). It is not reliable and sometimes detects the wrong encoding. Helpful global variables are e. g.
$current_encoding
,$evo_charset
and$io_charset
. -
When cycling through an array, never include the count function inside the loop’s condition. Make a variable to hold the result instead. Otherwise for each cycle of the loop, the size of the array will be re-calculated causing your program to become quite slow.
/* wrong */ for ( $i = 0; $i < count( $myArray ); $i++ ) { // Code } /* right */ $s = count( $myArray ); for ( $i = 0; $i < $s; $i++ ) { // Code }
-
When commenting code always include a space between the comment characters and the comment text.
/* wrong */ //My comment /* right */ // My comment
-
In PHP it is perfectly normal to use: breaks within a for loop, multiple returns in a function, and
die
s andexit
s within your code.
Inline code documentation
Technical documentation may be automatically generated by extracting comments form the source code, using phpDocumentor.
To document functions, objects, variables and other code elements, please add documentation to the source code in phpDocumentor format, which is actually very close to Javadoc format.
Anyhow, even if you don’t want to follow Javadoc format, do not restrain from adding comments to your code as well as to the existing code you’re currently trying to understand :P
SQL Guidelines
Escape input
Always use $DB->quote()
or $DB->escape()
on variables, that come from an untrusted source, which includes the user, of course!
Indenting is useful for SQL too!
Don’t write UPDATE table SET field = value WHERE field = condition
but:
UPDATE table
SET field = value
WHERE field = condition
Specifying field names
-
Never use an
INSERT INTO x VALUES( ... )
. -
Always specify which fields you act upon and in which order.
-
Also, if you really want all fields from a table, you can write
SELECT *
but you must address the fields by their name in PHP.
Keep in mind that tables change over time. New fields can get added. Other can get suppressed. Some can get reordered. Different upgrade paths may lead to different field orders accross users!
Quality and maintenance require explicit field naming in all SQL queries. Assuming a particular field order at any time is suicidal!
Miscellaneous
-
All SQL statements should be compatible with MySQL 5.1.
-
When you create a new table, take special care of the installation process. You need to handle new installations but also upgrades. Try to understand how the upgrade process works, especially the DB version number checking, before adding your code just anywhere.
CSS Guidelines
See CSS Guidelines.
These are great rules.
The EVO code is one of the most beautiful code I have seen and I am programing at lots of languages for many years.