The quality of a program begins with the quality of the source code. The fundamental factor for quality of source code is its readability and clarity. Formalized rules are necessary to write code which will be readable and understandable.
The rules for formatting code must be uniform throughout the entire project. It is highly desirable for the rules to be similar from project to project.
Note: The code formatting rules for core
D7 are somewhat different from the code formatting rules for
old core.
1. Source Code Formatting
1.1. Text Structure Rules
1.1.1. Line Length
Avoid typing lines whose length exceeds 120 characters. If a line spans beyond that limit, use the line wrapping rules described below.
1.1.2. Line Wrapping Rules
If a line length exceeds 120 characters, the following wrapping rules apply:
- wrap lines after the comma or before the operator;
- the wrapped line must be indented by one tab;
- use UNIX line ends.
Example 1: The code
$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD, $USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);
needs to be wrapped as follows:
$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD,
$USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);
Example 2: The code
if(COption::GetOptionString("main", "new_user_registration", "N")=="Y" && $_SERVER['REQUEST_METHOD']=='POST' &&$TYPE=="REGISTRATION" && (!defined("ADMIN_SECTION") || ADMIN_SECTION!==true))
needs to be wrapped as follows
if (COption::GetOptionString("main", "new_user_registration", "N") == "Y")
&& $_SERVER['REQUEST_METHOD'] == 'POST' && $TYPE == "REGISTRATION"
&& (!defined("ADMIN_SECTION") || ADMIN_SECTION !== true)
1.1.3. Spaces And Tabs
Use tabs for indentation. Using spaces for indentation is forbidden for the following reasons:
- with tabs, any developer can configure his or her text editor to show the desired tab length;
- using tabs makes file size smaller;
- if both tabs and spaces are used for indentation, the originally intended text formatting is likely to be damaged if a different tab size is used in a text editor.
1.1.4. Scopes And Code Blocks
The code block contents must be indented by one tab. The code block contents must not be on the same line as the controlling statement.
Example:
function func()
{
if (condition)
{
while (condition2)
{
}
}
}
1.1.5.Rules for placing braces
Opening braces must be place under a corresponding operator and on the same indent with it. Closing braces must be placed under the corresponding opening braces.
Example:
if ($condition)
{
...
}
1.1.6. Using the ternary operator "?:"
Conditions must be enclosed in parentheses, and thus separated from the rest of the code. As much as possible, actions that occur under these conditions should be simple functions. If an entire branched block reads poorly, then it is worth replacing it with if/else.
Example:
(condition ? funct1() : func2());
1.2. Expressions And Statements
1.2.1. Expressions
One line must contain only one expression.
Example. This expression is formatted incorrectly:
$a = $b; $b = $c; $c = $a;
Rewrite it like this:
$a = $b;
$b = $c;
$c = $a;
1.2.2. The statements if, else, while etc.
Use one of the following two formatting rules depending on the statement length.
if a controlled code block contains only one statement, use the following form:
if (expression)
statement 1;
else
statement 2;
if at least one controlled code block contains multiple statements, use braces:
if (expression)
{
statement 1;
}
else
{
statement 2;
statement 3;
}
The rule Scopes And Code Blocks must be obeyed when writing multiple statements: they must be indented by one tab off the controlling statement. The braces must exist on new lines on the same level as the controlling statement.
Example. This code:
if ($a == 0) $a = 10;
else{
$a = 5;
$b = 10;}
must be reformatted like this:
if ($a == 0)
{
$a = 10;
}
else
{
$a = 5;
$b = 10;
}
1.2.3. Compound Expressions
Compound expressions must be split in multiple lines according to rules described in “The statements if, else, while etc.”.
For example, consider the following code:
if(COption::GetOptionString("main", "new_user_registration", "N")=="Y" && $_SERVER['REQUEST_METHOD']=='POST' &&
$TYPE=="REGISTRATION" && (!defined("ADMIN_SECTION") || ADMIN_SECTION!==true))
Make it readable by sticking to the formatting rules:
if (COption::GetOptionString("main", "new_user_registration", "N") == "Y"
&& $_SERVER['REQUEST_METHOD'] == 'POST' && $TYPE == "REGISTRATION"
&& (!defined("ADMIN_SECTION") || ADMIN_SECTION !== true))
{
}
It is recommended that you split an extremely complex expression into several simple lines of code.
For example, the code
if((!(defined("STATISTIC_ONLY") && STATISTIC_ONLY && substr($APPLICATION->GetCurPage(), 0,
strlen(BX_ROOT."/admin/"))!=BX_ROOT."/admin/")) && COption::GetOptionString("main", "include_charset", "Y")=="Y"
&& strlen(LANG_CHARSET)>0)
is definitely more readable when written like this:
$publicStatisticOnly = False;
if (defined("STATISTIC_ONLY")
&& STATISTIC_ONLY
&& substr($APPLICATION->GetCurPage(), 0, strlen(BX_ROOT."/admin/")) != BX_ROOT."/admin/")
{
$publicStatisticOnly = True;
}
if (!$publicStatisticOnly && strlen(LANG_CHARSET) > 0
&& COption::GetOptionString("main", "include_charset", "Y") == "Y")
{
}
or like this:
if (!defined("STATISTIC_ONLY") || ! STATISTIC_ONLY
|| substr($APPLICATION->GetCurPage(), 0, strlen(BX_ROOT."/admin/")) == BX_ROOT."/admin/")
{
if (strlen(LANG_CHARSET) > 0 && COption::GetOptionString("main", "include_charset", "Y") == "Y")
{
}
}
1.2.4. Arrays
The arrays consisting of multiple lines of code should be formatted like this:
$arFilter = array(
"key1" => "value1",
"key2" => array(
"key21" => "value21",
"key22" => "value22",
)
);
1.3. Empty Lines And Spaces
1.3.1. Empty Lines
Use empty lines to logically divide your source code. Use multiple empty lines to divide the source code into logical or functional sections in one file. Use a single empty line to separate methods, as well as expressions and statements within a method for better readability.
It is recommended to add a comment before a logical or functional section (see Comments).
1.3.2. Spaces
The comma must be followed by the space. The semicolon must be followed by the space unless it is the last character on the line (for example, in a complex “for” statement). No spaces before the comma or semicolon is allowed. Tabs must not be used instead of spaces in such cases.
Use Cases
-
The following example shows how a space is used after the commas, but not before the parenthesis:
TestMethod($a, $b, $c);
These two code fragments are formatted incorrectly:
TestMethod($a,$b,$c);
and
TestMethod( $a, $b, $c );
- The following example shows to use spaces to properly separate the operators:
$a = $b * $c / $d;
as opposed to the same code formatted incorrectly:
$a=$b*$c/$d;
- Use spaces to format the “for” statements:
for ($i = 0; $i < 10; $i++)
- Do not merge operators and expressions like this:
for($i=0;$i<10;$i++)
- Note that using tabs to format expressions inside statements is not allowed.
The following formatting should not be made a common practice:
$arArray = array(
"key1" => "value1",
"key2" => "value2",
);
There is no special rule regarding the use of the space, or lack thereof, after the “if” statement.
1.4. Other regulations
Use parentheses to group operators in complex expressions regardless of operator precedence for better readability.
$r = $a + ($b * $c);
2. Naming Conventions
2.1. General Provisions
Do not use underscores in the identifier names because it makes them longer and less readable. Use such names that can describe the identifier purpose and meaning in an unambiguous fashion.
At the same time, try to make your identifier shorter (but they still must be well readable).
If a name contains an abbreviation, it’s better to use a single capital letter for the first letter of the abbreviation than to use capitals for the entire abbreviation. So it would be better to assign a name like getHtmlStatistic than getHTMLStatistic.
2.2. Variable Names
Start with a lowercase character and use uppercase character as separators (camelCase). Variable names can have prefixes if there is a clear need to show the type of variable: ar – for arrays, db – for data sets from databases, etc.
For example: $testCounter, $userPassword.
2.3. Method Names
- Clarity in action names, which will execute a function or method.
- Use of prefixes: is (indicates a question), get (to get a variable), set (set value).
Example: isFileWriteable()
2.4. Class Names
- The name should signify an entity described by the class.
- The name should not consist of more than 3 words.
- The underscore symbol (‘_’) cannot be used.
- To separate words in the name, the first letter of each word can be capitalized.
Example: class SaleAffiliateAccount
3. Comments
Commentary must be in English and contain relevant information
3.1. PHPDoc
All classes and their public methods must be described in PHPDoc style.
Example:
/**
* Gets a value that indicates whether a directory exists in the file system
*
* @param string $path - Path to the directory
* @return bool - True if the directory exists, false - otherwise
*/
4. Other
4.1. Magic numbers
Code should not contain magic numbers. Here is an example of bad code:
$task->Update($taskId, array('STATUS' => 3), 1);
Proper code:
$task->Update($taskId, array('STATUS' => CTaskStatus::New), TASK_PERMISSIONS_WRITE);
4.2. Automatic formatting tools
4.2.1. php_beautifier
1. Install the php_beautifier (ubuntu) pack:
sudo aptitude install php_beautifier or sudo aptitude install php-pear и sudo pear install PHP_Beautifier-0.1.15
cd
hg clone http://hg.max/repos/Bitrix_php_beautifier
sudo ln -s Bitrix_php_beautifier/Bitrix.filter.php /usr/share/php/PHP/Beautifier/Filter/Bitrix.filter.php
Configure the editor:
- Select the menu point Settings - Configure Kate...
- Select the setting Plugins and place a check next to Text Filter
- Click OK
- Now the Tools menu will have a point called Filter Text
Use:
- Select a text excerpt (or Ctrl-A for all the text)
- Tools - Filter Text
- Enter (or select from history): php_beautifier -t -f - -l 'Lowercase Bitrix'
- Click OK.