File Formatting
Indentation
Use an indent of 4 spaces with no tab characters. Editors should be configured to treat tabs as spaces in order to prevent injection of new tab characters into the source code.
Don't indent the main script level:
GOOD:
<?php
require('config.php');
$a = required_param('a', PARAM_INT);
if ($a > 10) {
call_some_error($a);
} else {
do_something_with($a);
}
BAD:
<?php
require('config.php');
$a = required_param('a', PARAM_INT);
if ($a > 10) {
call_some_error($a);
} else {
do_something_with($a);
}
SQL queries use special indentation, see SQL coding style.
Maximum Line Length
The key issue is readability.
Aim for 132 characters if it is convenient, it is not recommended to use more than 180 characters.
The exception are string files in the /lang directory where lines $string['id'] = 'value'; should have the value defined as a single string of any length, wrapped by quotes (no concatenation operators, no heredoc and no newdoc syntax). This helps to parse and process these string files without including them as a PHP code.
Wrapping lines
When wrapping a line, indent the follow-on line by 8 spaces rather than 4. For example:
if (a_long_condition() &&
a_nother_long_condition()) {
do_something();
}
Using eight spaces makes it easier to spot the difference between wrapped lines and indented blocks.
The example above is only an illustration; it is best practice to avoid wrapping lines in control structures. See below.
Wrapping Arrays
Associative arrays are a exception to the rule about 8-space indent for follow-on lines. The correct layout is:
$plugininfo['preferences'][$plugin] = array(
'id' => $plugin,
'link' => $pref_url,
'string' => $modulenamestr
);
Lining up the =>s is optional. Small arrays can be done on one line.
Wrapping function declarations
If you have many parameters, indent them in line with the first parameter:
public function graded_users_iterator($course, $grade_items = null, $groupid = 0,
$sortfield1 = 'lastname', $sortorder1 = 'ASC',
$sortfield2 = 'firstname', $sortorder2 = 'ASC') {
Wrapping Control Structures
If you have too many conditions in one control structure, try setting some variables before the start of the structure to improve readability.
GOOD:
$coursecategory = ($element['object']->is_course_item() or $element['object']->is_category_item());
$scalevalue = in_array($element['object']->gradetype, array(GRADE_TYPE_SCALE, GRADE_TYPE_VALUE));
if ($coursecategory and $scalevalue) {
BAD:
if (($element['object']->is_course_item() or $element['object']->is_category_item())
and ($element['object']->gradetype == GRADE_TYPE_SCALE
or $element['object']->gradetype == GRADE_TYPE_VALUE)) {
Method call wrapping
When wrapping a long line which consists of a chained series of functions, break the line at the end of each function, and continue the next chain on a new line.
The line should be indented by spaces.
The start of each line should contain the concatanation character, and the final line should contain a trailing semicolon.
Correct
var childNode = Y.Node.create('<div />')
.addClass(CSS.SOMECLASS)
.setAttribute('someAttribute', 'someValue')
.appendTo(parentNode);
Incorrect
// All on one line:
var childNode = Y.Node.create('<div />').addClass(CSS.SOMECLASS).setAttribute('someAttribute', 'someValue').appendTo(parentNode);
// A mix of separation and line concatanation:
var childNode = Y.Node.create('<div />').addClass(CSS.SOMECLASS)
.setAttribute('someAttribute', 'someValue').appendTo(parentNode);
// The concatanation character is at the end of the line:
var childNode = Y.Node.create('<div />').
addClass(CSS.SOMECLASS).
setAttribute('someAttribute', 'someValue').
appendTo(parentNode);
Line Termination
Use standard Unix text format. Lines must end only with a linefeed (LF). Linefeeds are represented as ordinal 10, or hexadecimal 0x0A.
Do not use carriage returns (CR) like old Macintosh computers (0x0D).
Do not use the carriage return/linefeed combination (CRLF) as Windows computers (0x0D, 0x0A).
Lines should not contain trailing spaces. In order to facilitate this convention, most editors can be configured to strip trailing spaces, such as upon a save operation. However, if you are editing an existing Moodle file and are planning to submit your changes for integration, please switch off that feature so that whitespace changes do not pollute the patch (other developers will have trouble viewing what you've done if every other line has been edited for whitespace).
Naming Conventions
Filenames
Filenames should :
- be whole english words
- be as short as possible
- use lowercase letters only
- end in .php, .html, .js, .css or .xml
Class naming
Classes should be named using CamelCase starting with an uppercase letter.
This helps to clearly separate variables, and standard functions from those used to create a new instance.
Correct
// The instantiator:
function Pantry() {
// Setup code goes here.
}
// Making use of it:
var myPantry = new Pantry();
// And another:
function PantryShelf() {
}
var myPantryShelf = new PantryShelf();
Incorrect
// There is no distinction here between a normal function, and one used to
// create a new object:
function pantry() {
}
// This results in an unclear object creation:
var myPantry = new pantry();
// This one is also incorrect, despite using camelCase:
function pantryShelf() {
}
var myPantryShelf = new pantryShelf();
// This one is also incorrect:
function pantry_shelf() {
}
var myPantryShelf = new pantry_shelf();
Variable and function naming
Contrary to the standard Moodle coding style, camelCase should be used to name variables and functions in JavaScript.
Correct
var currentY,
courseCategory,
lastValue,
lastBackgroundColor;
function doSomething() {
// Do stuff here.
}
function doSomethingElse() {
// Do stuff here.
}
var someFunction = function() {
// Do stuff here.
};
Incorrect
var current_y,
currenty,
course_category,
coursecategory,
last_value,
lastvalue,
last_background_color,
lastbackgroundcolor;
function dosomething() {
}
function do_something_else() {
}
var somefunction = function() {
};
var some_other_function = function() {
};
var somevalue = null;
if (someTest) {
somevalue = function() {
return (something && complicated || somethingelse);
};
} else {
somevalue = 'basicvalue';
}
Function Parameters
Parameters are always simple lowercase English words (sometimes more than one, like $initialvalue), and should always have sensible defaults if possible.
Use "null" as the default value instead of "false" for situations like this where a default value isn't needed.
public function foo($required, $optional = null)
However, if an optional parameter is boolean, and its logical default value should be true, or false, then using true or false is acceptable.
Constants
Variables intended to be constants should use the same naming style of ALL UPPERCASE.
Constants are recommended for use in the following scenarios:
- CSS: An object containing any CSS classes you may wish to use with Nodes; and
- SELECTORS: An object containing query selectors for selecting Nodes.
Booleans and the null value
Use lower case for true, false and null.
Variables
All variables must:
- be declared before they are used and using the var keyword;
- be declared once, and only once, for the scope in which they are used;
- only be declared if they are to be used; and
- use sensible naming, following the naming convention.
Strings
Since string performance is not an issue in current versions of PHP, the main criteria for strings is readability.
Single quotes
Always use single quotes when a string is literal, or contains a lot of double quotes (like HTML):
$a = 'Example string';
echo '<span class="'.s($class).'"></span>';
$html = '<a href="http://something" title="something">Link</a>';
Double quotes
These are a lot less useful in Moodle. Use double quotes when you need to include plain variables or a lot of single quotes.
echo "<span>$string</span>";
$statement = "You aren't serious!";
Complex SQL queries should be always enclosed in double quotes.
$sql = "SELECT e.*, ue.userid
FROM {user_enrolments} ue
JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'self' AND e.customint2 > 0)
JOIN {user} u ON u.id = ue.userid
WHERE :now - u.lastaccess > e.customint2";
Variable substitution
Variable substitution can use either of these forms:
$greeting = "Hello $name, welcome back!";
$greeting = "Hello {$name}, welcome back!";
String concatenation
Strings must be concatenated using the "." operator.
$longstring = $several.$short.'strings';
If the lines are long, break the statement into multiple lines to improve readability. In these cases, put the "dot" at the end of each line.
$string = 'This is a very long and stupid string because '.$editorname.
" couldn't think of a better example at the time.";
The dot operator may be used without any space to either side (as shown in the above examples), or with spaces on each side; whichever the developer prefers.
Arrays
Numerically indexed arrays
When declaring indexed arrays with the array function, a trailing space must be added after each comma delimiter to improve readability:
$myarray = array(1, 2, 3, 'Stuff', 'Here');
Multi-line indexed arrays are fine, but pad each successive lines as above with an 8-space indent:
$myarray = array(
1, 2, 3, 'Stuff', 'Here',
$a, $b, $c, 56.44, $d, 500);
Associative arrays
Use multiple lines if this helps readability. For example:
$myarray = array(
'firstkey' => 'firstvalue',
'secondkey' => 'secondvalue'
);
Classes
Class declarations
- Classes must be named according to Moodle's naming conventions.
- The brace should always be written on the line beside the class name.
- Every class must have a documentation block that conforms to the PHPDocumentor standard.
- All code in a class must be indented with 4 spaces.
- Placing additional code in class files is permitted but discouraged. In such files, two blank lines must separate the class from any additional PHP code in the class file.
- An example:
/**
* Documentation Block Here
*/
class sample_class {
// All contents of class
// must be indented 4 spaces.
}
Class member variables
In the case of object property assignment, there should be a space after the colon, but not before.
Correct
var anObject = {
someKey: 'someValue',
anotherKey: Y.one(SELECTORS.FOO)
};
Incorrect
var anObject = {
// Incorrect because a space is present both before and after the assignation character:
someKey : 'someValue',
// Incorrect because there is no whitespace either side of the assignation character:
anotherKey:Y.one(SELECTORS.FOO)
};
Functions and methods
Function and method declaration
Functions must be named according to the Moodle function naming conventions.
Methods inside classes must always declare their visibility by using one of the private, protected, or public modifiers.
As with classes, the brace should always be written on same line as the function name.
Don't leave spaces between the function name and the opening parenthesis for the arguments.
The return value must not be enclosed in parentheses. This can hinder readability, in additional to breaking code if a method is later changed to return by reference.
Return should only be one data type. It is discouraged to have multiple return types
/**
* Documentation Block Here
*/
class sample_class {
/**
* Documentation Block Here
*/
public function sample_function() {
// All contents of function
// must be indented four spaces.
return true;
}
}
Function and method usage
Function arguments should be separated by a single trailing space after the comma delimiter.
three_arguments(1, 2, 3);
Control statements
In general, use white space liberally between lines and so on, to add clarity.
If / else
Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets. Use inner brackets to improve logical grouping if it helps.
Indent with four spaces.
Don't use elseif!
Always use braces (even if the block is one line and PHP doesn't require it).
if ($x == $y) {
$a = $b;
} else if ($x == $z) {
$a = $c;
} else {
$a = $d;
}
Switch
Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets. Use inner brackets to improve logical grouping if it helps.
Always indent with four spaces. Content under each case statement should be indented a further four spaces.
switch ($something) {
case 1:
break;
case 2:
break;
default:
break;
}
Foreach
As above, uses spaces like this:
foreach ($objects as $key => $thing) {
process($thing);
}
Ternary Operator
The ternary operator is only permitted to be used for short, simple to understand statements. If the statement can't be understood in one sentance, use an if statement instead.
Whitespace must be used around the operators to make it clear where the operation is taking place.
GOOD:
$username = isset($user->username) ? $user->username : '';
BAD:
$toload = (empty($CFG->navshowallcourses))?self::LOAD_ROOT_CATEGORIES:self::LOAD_ALL_CATEGORIES;
$coefstring = ($coefstring=='' or $coefstring=='aggregationcoefextrasum') ? 'aggregationcoefextrasum' : 'aggregationcoef';
Operators
There should be a space at either side of all binary operators to help improve legibility of code. This includes:
- =
- &&
- ||
- ===
- +
- -
- /
- *
There should be no space around unary operators. This includes:
- !
- ++
- --
There should be no space around the function operator (.)
Correct
// Valid binary operators:
var a = 1,
b = (a && 1),
c = (b || 1),
d = (b === c),
e = Y.Node.create('<div>Some Content</div>');
// No space around the . operator when it's not a continuation:
e.someFunctionCall();
// Whitespace is allowed for a function operator when it is a continuation starting on a new line:
e.someFunction()
.someOtherFunction()
.someFinalFunction();
// Unary operators should not be separated by whitespace:
a = a++;
b = b--;
c = (!e.someResult());
// An example bringing most of these together:
var index,
loopTest = 0;
for (index = 0; (!loopTest <= (a / b * (c + d - e.getValue()))); index++) {
loopTest = index * 12;
}
Incorrect
var a=1,
b= (a&&1),
c =(b||1),
d = (b===c);
a = a ++;
b =b++;
c= c++;
d = d++ ;
var e = Y . Node . create('<div>Some content</div>');
for ( index = 0;index<a; index ++ ) {
}
Documentation and comments
Modules should be documented using the standard YUI guidance: http://yui.github.io/yuidoc/syntax/index.html.
General notes
- Unless otherwise specified, comments should conform to the general style guidelines;
- all comments must start with leading whitespace before the first word on each line; and
- all indentation must be in addition to any existing leading whitespace on the line.
Official documentation
All JavaScript documentation must:
- use the correct docblock format;
- use the correct JavaScript types where relevant (note, Int is not a valid type in JavaScript);
- use all appropriate tags;
- produce valid documentation using the YUIDoc toolset;
- have a linebreak between the description and the list of tags.
Note:
YUIDoc will only generate documentation for docblocks starting with /**.
YUIDoc will try to generate documentation for *all* docblocks starting /**.
Correct
/**
* This docblock describes a YUI module.
*
* @module moodle-mod_food-marmite
*/
/**
* This docblock describes the marmite class within the
* moodle-mod_food-marmite module.
*
* @class Marmite
*/
/**
* This is an example docblock comment. It describes a function called
* marmite.
*
* It adds a number of jars of marmite to the cupboard.
*
* @method addMarmite
* @param {Number} [jarCount=1] The number of jars of marmite to add to the
* cupboard. This parameter is optional and defaults to 1.
* @chainable
*/
/**
* This docblock describes the property weight, in grams.
*
* @property weight
* @type {Number}
* @default '500'
*/
/**
* This docblock describes an attribute.
*
* @attribute weight
* @type {Number}
* @default '500'
*/
Incorrect
/*
* This is an invalid comment block. It wouldn't be picked up by yuidoc as
* the comment style is incorrect.
*
* @method foo
*/
// This is also an invalid comment block and wouldn't be picked up by
// YUIDoc.
/**
* Although this style would be picked up by YUIDoc, it is hard to read.
*
* @method foo
*/
/**
*Although this style would be picked up by YUIDoc, it is also hard to read.
*
*@method foo
*/
/**
* This docblock is mostly valid but does not include a linebreak between
* the description, and the tags.
* @method foo
*/
General comments
All shorter comments, for example those explaining the subsequent few lines of code should use the // style of comments.
Comments not intended for official documentation must *not* use the Docblock style of commenting as YUIDoc will attempt to include the comment in official documentation.
Correct
// This is a valid set of comments for one line.
// And this is a valid longer comment to describe the subsequent few lines
// in as much detail as required. It can consist of multiple sentences, as
// long as each new line starts with the correct comment style.
Incorrect
/* This is an invalid comment style for short comments. */
//This is also an invalid style as there is no leading whitespace after the
//comment indicator.
/**
* This is an invalid multi-line comment. Multi-line comments should not
* use the docblock style comments unless they are a valid and fully
* formatted docblock.
*/
/*
* This is an also invalid multi-line comment. Although it is not a full
* docblock style, it does not start with the // style of comment
* indicator.
*/