Combodo Coding Standards
This page is a brief description of the iTop coding conventions (mostly for PHP). The iTop coding conventions share a lot with the PSR-2 standard, but there are also quite a few significant differences, beware!
The source code files are encoded in UTF-8 (without a BOM at the beginning of the file).
The line feeds must be Lf.
PHP files must use the long PHP opening tag at the beginning of
the file <?php
but must not contain any PHP closing
tag. This prevents extra blank characters to be added by mistake at
the end of the file… where they will be appended to the output
produced by the page.
White spaces and indentation
The indentation is made using :
-
PHP files : tabulations (configure your editor to display a tab as 4 characters wide)
-
SCSS : 2 spaces
-
Twig : 4 spaces
Opening braces for if/else, try/catch, while, switch, anonymous classes must be at the end of the line, and closing braces must go on the next line after the body. For classes and functions we are keeping opening braces on the next line.
Example:
class NiceWebPage extends WebPage { ... public function SetContentType($sContentType) { if ($sContentType == '') { // Do something } else { // Do something different } } }
When writing function calls, the arguments supplied (between parentheses) immediately after the name of the function: there is no space between the function name and the arguments list. The comma in each arguments list is followed by a space.
Example:
$sValue = Utils::ReadParam('param1', 'default_value');
The binary operators (==
, +
,
&&
) are surrounded by spaces.
Exception: the concatenation operator .
is not
surrounded by spaces since this tends to keep lines more compact
and does not reduce the readability of the code when using
non-proportional fonts.
Example:
if (isset($aPerson[$this->iPersonId][0]) && ($aPerson[$this->iPersonId][0] != "")) { if ($this->sSynchronizeOrganization == 'yes') { $sName = $aPerson[$this->iPersonId]['first_name'].' '.$aPerson[$this->iPersonId]['last_name']; } }
Strings delimiter
You can use any of the delimiter you prefer, the main goal is to keep the code readable.
When using heredoc / nowdoc, we recommend using delimiters that allows JetBrains' language injection.
Examples :
$sHtml = '<a href="http://www.combodo.com">'; $sFooBarBaz = "{$foo}-{$bar} {$baz}"; $sJs = <<<JS console.debug("this is some JS code"); console.debug("having the right delimiter keyword will help language injection !"); JS;
Variables naming
Variables, function parameters and object properties are named using a mixed case convention (i.e. all lowercase with an uppercase letter at the beginning of each word) and a prefix letter used as a type hint:
-
the
a
prefix is used for hash or arrays (PHP does not make any difference: each array is actually a hash) -
the
i
prefix is used of for integers -
the
o
prefix is used for PHP objects -
the
s
prefix is used for strings -
more rarely used:
f
for floating point numbers (i.e. non integer numbers),r
orh
can be used for resource handles.
Example:
<?php $iCount = 1; $sText = 'This is a text'; $oPage = new WebPage('test'); $fRank = 1.25; $hDir = opendir('/opt'); // No PHP closing tag
A variable with no prefix is supposed to be of mixed type (can be either a string, an array or an object)
Example:
public function Set($sAttCode, $value) { ... }
Allowed Exceptions
-
Local variables used for loop counters (e.g.
$i
,$j
) may have no prefix. -
In mathematical computations involving a lot of numeric variables it is acceptable to drop the prefix for such variables (e.g.
$x
,$y
,$xMax
…) -
For historical reasons, the WebPage class (and the related classes) as well as some parts inside MetaModel use a different convention: variables are all lowercase with an underscore character to separate words. Object properties (members) are prefixed using the
m_
prefix.
Array key naming
We are using Snake case for array keys.
Example :
$aMyArray = [ 'value_raw' => $sMyValue, 'input_id' => $iInputId, ];
Please document the keys using the appropriate PHPDoc syntax (see below)
Configuration parameter naming
You shoud use lower case and separate words with an underscore character.
When multiple configuration parameters relates to the same subject, they can be grouped using a prefix ending with a dot character.
For example : email_transport_smtp.host
Functions naming (PHP, JS)
Functions and object methods are named using a mixed case convention (i.e. all lowercase with an uppercase letter at the beginning of each word). Even if PHP is not case sensitive for the function names, this useful to distinguish the functions which are part of the project from PHP's built-in functions which are generally written in lowercase. The function names are generally based on a verb expressing the action being performed.
Example:
function DisplayWelcomePopup(WebPage $oP) { // Code goes here }
Visibility MUST be declared on all properties and methods; abstract and final MUST be declared before the visibility; static MUST be declared after the visibility.
Type hinting
PHP type hinting (adding types in method signatures in PHP) is possible since iTop 3.0.0 (PHP 7.1.3 is its minimal version), but :
-
only use php type hinting on new code, do not modify existing methods
-
mind to follow the minimal PHP version capabilities (for example union types are available only since PHP 8.0.0, see PHP: Type declarations - Manual)
-
on fluid methods, don't add the return type as it would cause issues on inheritance
Comparisons ( == vs === )
Since 22/12/2022 it has been decided that strict comparison ( === ) becomes the standard rule for all new developments.
Exception:
-
We don't really known the types of the compared data, in that case prefer a strict comparison ( === ) with a cast to make it explicit.
-
If this is not possible, soft comparison ( == ) is tolerated but only if it comes with both an annotation to suppress the PHPStorm warning and a comment to explain why the soft comparison was the only way.
Patterns to avoid
Test if a string is empty with empty()
When you want to check if a string is empty, don't use
empty()
but strlen() > 0
instead (or
even better \utils::IsNullOrEmptyString()
if you code
is meant for iTop 3.0.2+)
in some cases a variable can contain “0”
which is
evaluated as true by empty(“0”)
.
$sFoo = ''; // Don't if (empty($sFoo)) { // Some stuff } // Do // - iTop 2.7+ if (strlen($sFoo) === 0) { // Some stuff } // - iTop 3.0.2+ if (\utils::IsNullOrEmptyString($sFoo)) { // Some stuff }
PhpDoc
The rules to write PhpDoc are described in the repository itself : see /.doc/README.md.
@since
We are also using the @since tag to indicate API methods introduction or modifications.
Example :
/** * ... * * @since 2.5.2 2.6.0 new 'transaction_id' filter * @since 2.7.0 new 'element_identifier' filter * @since 3.0.0 new utils::ENUM_SANITIZATION_* const * @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter */ protected static function Sanitize_Internal($value, $sSanitizationFilter)
Bool VS boolean
Please use bool
in the PHPDoc, because :
Arrays : psalm/phpstan syntax
Example :
/**
* ...
* @return array<string, \CheckResult> full path as key, CheckResult error as value
*/
See the corresponding documentations :
Arrays with named keys : array Shapes
Example :
/** * @param array{ * languageCode: string, * entries: array{ * code: string, * value: string * } * } $aDictData */ public static $aDictData;
See the following documentations :
Dictionnaries entries
This is a subject by itself, see the dedicated wiki page : How to translate