Actions

Difference between revisions of "Developer Area/Coding guidelines"

From Mahara Wiki

< Developer Area
(Created page with "This page documents the coding conventions used by Mahara. Everything that ends up in the git repository should follow these standards. <div id="section_1"> === The Basics === …")
 
(syntax highlight)
 
(60 intermediate revisions by 8 users not shown)
Line 1: Line 1:
This page documents the coding conventions used by Mahara. Everything that ends up in the git repository should follow these standards.
+
This page documents the coding conventions used by Mahara. Everything that ends up in the git repository (other than third-party code) should follow these standards.
  
<div id="section_1">
+
You can also have a look at the [[Developer_Area/How_to_Review_Code|Reviewer's manual]] to see what reviewers will look at when looking at code submissions.
  
=== The Basics ===
+
Separate pages with more information:
 +
 
 +
* [[Developer_Area/Coding_guidelines/PHP_files|PHP Files]]
 +
* [[Developer_Area/Coding_guidelines/JS_files|JavaScript Files (or snippets)]]
 +
* [[Developer_Area/Coding_guidelines/TPL_files|TPL Files (may change in future if move away from smarty, ie to twig)]]
 +
 
 +
 
 +
=Accessibility=
 +
 
 +
Mahara should be accessible to anybody. We are aiming to follow the [https://www.w3.org/TR/WCAG21/ WCAG 2.1] AA principles. There are a [https://blueprints.launchpad.net/mahara/+spec/wcag2.1 areas that we identified that require changes] to achieve that aim. New and changed code should always be written with accessibility principles and guidelines in mind rather than tagged on 'when there is time'. Writing code accessible from the start makes it better code and requires less refactoring later on.
 +
 
 +
The style guide, accessible via 'yourmaharadomain/theme/styleguide.php', gives useful basic information for a lot of style elements.
 +
 
 +
Since the field of accessibility is changing, certain elements may require updates over time. You can find more information on our [https://wiki.mahara.org/wiki/Accessibility 'Accessibility' page].
 +
 
 +
=File Headers=
  
 
All files must adhere to the [[BasicPHPFileTemplates]]. There are slightly different templates depending on whether the script is to be included or whether it is to be directly hit.
 
All files must adhere to the [[BasicPHPFileTemplates]]. There are slightly different templates depending on whether the script is to be included or whether it is to be directly hit.
  
Indentation is using four (4) spaces. There is no requirement that the scripts are wrapped at 80 columns, however developers are asked to wrap long lines sensibly.
+
Closing php tags ?> should be omitted.
  
</div><div id="section_2">
+
=Whitespace=
  
=== Comments ===
+
'''Required:'''
 +
* Indentation is using four (4) spaces, '''not''' tabs.
 +
* Line endings should be "Unix-style" (\n), not "Windows-style" (\r\n).
 +
* Avoid extra whitespace at the end of modified lines.
 +
* Avoid editing whitespaces unrelated to your specific code change, when submitting a patch. It makes reviewing the patch more difficult and add unnecessary noise to the change history.
  
Comments of up to three lines in length should use the // comment marker. Comments longer than three lines should use /* ... */. Here is an example comment:
 
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">/*<br />    This part is difficult, and requires a long<br />    explanation. This is that explanation. I am<br />    still typing to see if I can make it to four<br />    lines.<br /> */<br /></font> </font> </code></div>
+
'''Recommended:'''
 +
* There is no requirement that the scripts are wrapped at 80 columns, however developers are asked to wrap long lines sensibly.
  
Please note that the opening and ending markers are on their own lines - nothing else should be on these lines.
+
=Language Constructs=
  
</div><div id="section_3">
 
  
=== Language Constructs ===
+
==switch/case statements==
  
<div id="section_4">
+
"case" should use multiline formatting:
  
==== Strings ====
+
<syntaxhighlight lang="php">
 +
switch ($var) {
 +
    case 1:
 +
        a = 25;
 +
        b = 100;
 +
        break;
 +
    default:
 +
        a = 0;
 +
        b = 0;
 +
}
 +
</syntaxhighlight>
 +
NOT
 +
<syntaxhighlight lang="php">
 +
case 1: a = 25; b = 100; break;
 +
</syntaxhighlight>
  
Strings should be quoted with single quotes (') unless you are interpolating a variable.
+
==Variables and Arrays==
  
</div><div id="section_5">
+
Variables should be named with no underscores, and no capital letters. This policy may become more lenient in future if variable names are discovered that are not easily readable without underscores.
  
==== require/require_once/include/include_once ====
+
Do not name variables as negatives where possible - always use positive names and logical inversion (!) where required.
  
These statements should have brackets around the argument. There is no space between the statement and the bracket. In effect, this is the same as a function call.
+
Hungarian notation is forbidden.
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">require_once(</font><font color="#dd0000">'my/file.php'</font><font color="#007700">);<br /></font> </font> </code></div>
+
Aligning = signs for variable assignment is up to the developer, although they should use common sense in such decisions.
  
'''NOT'''<nowiki>:</nowiki>
+
Hardcoded binary data is not allowed for security reasons.
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">require_once </font><font color="#dd0000">'my/file.php'</font><font color="#007700"><nowiki>;</nowiki><br /> require_once (</font><font color="#dd0000">'my/file.php'</font><font color="#007700">);<br /></font> </font> </code></div>
+
Hardcoded serialised data is not allowed for security reasons.
  
Plugin files '''must''' be included using the [http://mahara.eduforge.org/api/mahara/core/_lib---mahara.php.html#functionsafe_require <span style="white-space: nowrap">[[Image:http.png]]safe_require</span>] function. This function ensures that there are no vulnerabilities in accessing a plugin file. Plugins that do not use this function to include files should be considered vulnerable to a possible security vulnerability.
+
Good:
 +
<syntaxhighlight lang="php">
 +
$found = false;
 +
$ponies = 0;
 +
$servername = $overkill;
  
Any include statements in the core should '''never''' have a variable in their name, to reduce the chance of an arbitary include vulnerability.
+
// Only in relation to controlling for/while loops
 +
for ($i = 10; $i > 5; $i--) {
 +
    echo $i;
 +
}
  
The include path is set automatically to be the current directory plus the lib directory - there is no need to specify an absolute directory path.
+
// Aligning = signs
 +
$mine  = 0;
 +
$yours  = 0;
 +
$theirs = 0;
  
</div><div id="section_6">
+
// Only if the number of elements to initialise is small.
 +
$array = array(1 => 'hello');
  
==== if/while/for statements ====
+
// If large number of elements to initialise:
 +
$array = array(
 +
    1  => 'hello',
 +
    2  => 'goodbye',
 +
    10 => 'erm'
 +
);
 +
</syntaxhighlight>
 +
Bad:
 +
<syntaxhighlight lang="php">
 +
// Negative name
 +
$notfound = true;
 +
// Underscores
 +
$my_variable = '';
 +
// Hungarian
 +
$count_i = 6;
 +
// Uppercase letters
 +
$myFish = $yourFish;
  
There is one space after each language construct, and no spaces between brackets and the arguments inside them, '''unless''' what is inside them becomes too long for one line, in which case a special format will be used.
+
$array = array(
 +
                1 => 'hello',
 +
                2 => 'goodbye',
 +
                10 => 'erm'
 +
              );
 +
</syntaxhighlight>
  
Examples of what is '''good'''<nowiki>:</nowiki>
+
==Binary Operators==
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">if (</font><font color="#0000bb">1 </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">2</font><font color="#007700">) {<br />     die(</font><font color="#dd0000">'omg'</font><font color="#007700">);<br /> }<br /><br /> while (</font><font color="#0000bb">$i </font><font color="#007700">&lt; </font><font color="#0000bb">3</font><font color="#007700">) {<br />     echo </font><font color="#dd0000">'I am ' </font><font color="#007700">. </font><font color="#0000bb">$i</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /> for (</font><font color="#0000bb">$i </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">0</font><font color="#007700">, </font><font color="#0000bb">$j </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">7</font><font color="#007700"><nowiki>; </nowiki></font><font color="#0000bb">$i </font><font color="#007700">&lt; </font><font color="#0000bb">34</font><font color="#007700">, </font><font color="#0000bb">$j </font><font color="#007700"><nowiki>!= </nowiki></font><font color="#0000bb">3</font><font color="#007700"><nowiki>; </nowiki></font><font color="#0000bb">$i</font><font color="#007700">++, </font><font color="#0000bb">$j</font><font color="#007700">--) {<br />     echo (</font><font color="#0000bb">$i </font><font color="#007700"><nowiki>* </nowiki></font><font color="#0000bb">$j</font><font color="#007700">) . </font><font color="#dd0000">' is a silly number'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /></font><font color="#ff8000">// Note bracing style of else if/else clauses<br /> // Also note: do not use elseif<br /></font><font color="#007700">if (</font><font color="#0000bb">$a </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$b</font><font color="#007700">) {<br />     echo </font><font color="#dd0000">"a = b"</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /> else if (</font><font color="#0000bb">$c </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$d</font><font color="#007700">) {<br />     echo </font><font color="#dd0000">"c = d"</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /> else {<br />     echo </font><font color="#dd0000">"e = ?"</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /></font><font color="#ff8000">// Ternary operator<br /></font><font color="#0000bb">$a </font><font color="#007700"><nowiki>= (</nowiki></font><font color="#0000bb">$b </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">true</font><font color="#007700">) ? </font><font color="#dd0000">'hello' </font><font color="#007700"><nowiki>: </nowiki></font><font color="#dd0000">'goodbye'</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#ff8000">// When used with other things on each side in the same statement:<br /></font><font color="#0000bb">$a </font><font color="#007700"><nowiki>= </nowiki></font><font color="#dd0000">'foo' </font><font color="#007700">. ((</font><font color="#0000bb">$b </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">true</font><font color="#007700">) ? </font><font color="#dd0000">'hello' </font><font color="#007700"><nowiki>: </nowiki></font><font color="#dd0000">'goodbye'</font><font color="#007700">) . </font><font color="#dd0000">'bar'</font><font color="#007700"><nowiki>;</nowiki><br /><br /></font><font color="#ff8000">// A complicated condition. Note location of condition,<br /> // and location of ending bracket and brace.<br /> // todo: what was the decision here regarding conditions on the "if (" line?<br /></font><font color="#007700">if (<br />     </font><font color="#0000bb">$sacrificedgoats </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$availablegoats<br />     </font><font color="#007700">&amp;&amp; (</font><font color="#0000bb">$dogs </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$cats<br />     </font><font color="#007700"><nowiki>|| </nowiki></font><font color="#0000bb">1 </font><font color="#007700"><nowiki>!= </nowiki></font><font color="#0000bb">2</font><font color="#007700">)<br />     || (</font><font color="#0000bb">$yesterday </font><font color="#007700">&gt;&gt; </font><font color="#0000bb">$tomorrow </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">4</font><font color="#007700">)<br /> ) {<br />     </font><font color="#ff8000">// Do stuff<br /></font><font color="#007700">}<br /></font> </font> </code></div>
+
Always have a space on each side:
 +
<syntaxhighlight lang="php">
 +
echo 1 + 2;
 +
if (1 == 2)
 +
echo 'hello' . ' world';
 +
</syntaxhighlight>
  
Examples of what is '''bad'''<nowiki>:</nowiki>
+
<syntaxhighlight lang="text" inline>||</syntaxhighlight> and <syntaxhighlight lang="text" inline>&&</syntaxhighlight> will always be used for <syntaxhighlight lang="text" inline>or</syntaxhighlight> and <syntaxhighlight lang="text" inline>and</syntaxhighlight> respectively. Resolve priority collisions with extra parentheses as required.
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">if ( </font><font color="#0000bb">$a </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$b </font><font color="#007700">)<br /> {<br />     echo </font><font color="#dd0000">'hi'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /> if(</font><font color="#0000bb">$c </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$d</font><font color="#007700">) {<br />     echo </font><font color="#dd0000">'hi'</font><font color="#007700"><nowiki>;</nowiki><br /> } else {<br />     echo </font><font color="#dd0000">'bye'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /> if (</font><font color="#0000bb">$e</font><font color="#007700"><nowiki>==</nowiki></font><font color="#0000bb">$f</font><font color="#007700">)<br /> {<br />     echo </font><font color="#dd0000">'hi'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /> else<br /> {<br />     echo </font><font color="#dd0000">'bye'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /></font> </font> </code></div>
+
==Classes, Functions and Methods==
  
What should be '''never''' used:
+
'''Nameing'''
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">// For a really short condition<br /></font><font color="#007700">if (</font><font color="#0000bb">$a </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">$b</font><font color="#007700">) </font><font color="#0000bb">$c </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">1</font><font color="#007700"><nowiki>;</nowiki><br /><br /></font><font color="#ff8000">// Just don't. Not even ow.<br /></font><font color="#007700">do {<br />     echo </font><font color="#dd0000">'hi'</font><font color="#007700"><nowiki>;</nowiki><br /> } while (</font><font color="#0000bb">$a </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">1</font><font color="#007700">);<br /></font> </font> </code></div></div><div id="section_7">
+
Classes should start with upper case character, then each word capitalized.
  
==== Variables and Arrays ====
+
<syntaxhighlight lang="php">
 +
class ExampleWhizbang {
 +
    // ...
 +
}
 +
</syntaxhighlight>
  
Variables should be named with no underscores, and no capital letters. This policy may become more lenient in future if variable names are discovered that are not easily readable without underscores.
+
Leave double empty line between classes blocks in the code.
  
Do not name variables as negatives where possible - always use positive names and logical inversion (!) where required.
+
Functions should not use camel case, and instead use underscores as word separators
  
Hungarian notation is forbidden.
+
<syntaxhighlight lang="php">
 +
function do_something(){
 +
    // ...
 +
}
 +
</syntaxhighlight>
  
When related variables are initialised, the = signs for them should line up. Other than that, aligning = signs for variable assignment is up to the developer, although they should use common sense in such decisions.
+
NOT
 +
<syntaxhighlight lang="php">
 +
function doSomething() {
 +
    // ...
 +
}
 +
</syntaxhighlight>
  
Good:
+
Function name must start with a letter (no _ character before function name, unless you declare magic method where double underscore is used).
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#0000bb">$found </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">false</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#0000bb">$ponies </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">0</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#0000bb">$servername </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">$overkill</font><font color="#007700"><nowiki>;</nowiki><br /><br /></font><font color="#ff8000">// Only in relation to controlling for/while loops<br /></font><font color="#007700">for (</font><font color="#0000bb">$i </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">10</font><font color="#007700"><nowiki>; </nowiki></font><font color="#0000bb">$i </font><font color="#007700">&gt; </font><font color="#0000bb">5</font><font color="#007700"><nowiki>; </nowiki></font><font color="#0000bb">$i</font><font color="#007700">--) {<br />     echo </font><font color="#0000bb">$i</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /></font><font color="#ff8000">// Aligning = signs<br /></font><font color="#0000bb">$mine   </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">0</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#0000bb">$yours  </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">0</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#0000bb">$theirs </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">0</font><font color="#007700"><nowiki>;</nowiki><br /><br /></font><font color="#ff8000">// Only if the number of elements to initialise is small.<br /></font><font color="#0000bb">$array </font><font color="#007700"><nowiki>= array(</nowiki></font><font color="#0000bb">1 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'hello'</font><font color="#007700">);<br /><br /></font><font color="#ff8000">// If large number of elements to initialise:<br /></font><font color="#0000bb">$array </font><font color="#007700"><nowiki>= array(</nowiki><br />     </font><font color="#0000bb">1  </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'hello'</font><font color="#007700">,<br />     </font><font color="#0000bb">2  </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'goodbye'</font><font color="#007700">,<br />     </font><font color="#0000bb">10 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'erm'<br /></font><font color="#007700">);<br /></font> </font> </code></div>
+
Leave single empty line between two function blocks and between function block and code if function is used in non-library file.
  
Bad:
+
The built-in PHP class <code>[http://php.net/manual/en/reserved.classes.php "stdClass"]</code> should be written with a lowercase s, uppercase C, because that is its actual name. Other capitalizations, such as "StdClass" will not cause an error because invocations of classnames and functions are case-insensitive in PHP. However, it is good style to use the same capitalization as the declaration of the class/function.
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">// Negative name<br /></font><font color="#0000bb">$notfound </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">true</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#ff8000">// Underscores<br /></font><font color="#0000bb">$my_variable </font><font color="#007700"><nowiki>= </nowiki></font><font color="#dd0000"><nowiki>''</nowiki></font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#ff8000">// Hungarian. Eew....<br /></font><font color="#0000bb">$count_i </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">6</font><font color="#007700"><nowiki>;</nowiki><br /></font><font color="#ff8000">// Uppercase letters<br /></font><font color="#0000bb">$myFish </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">$yourFish</font><font color="#007700"><nowiki>;</nowiki><br /><br /></font><font color="#ff8000">// Not necessarily "bad", just not for this project<br /></font><font color="#0000bb">$array </font><font color="#007700"><nowiki>= array(</nowiki><br />                 </font><font color="#0000bb">1 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'hello'</font><font color="#007700">,<br />                 </font><font color="#0000bb">2 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'goodbye'</font><font color="#007700">,<br />                 </font><font color="#0000bb">10 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'erm'<br />               </font><font color="#007700">);<br /></font> </font> </code></div></div><div id="section_8">
+
Constructors without arguments should be called with empty parentheses after them.
  
==== Binary Operators ====
+
Good:
  
Always have a space on each side:
+
<syntaxhighlight lang="php">
 +
$a = new stdClass();
 +
$b = new RssBlock();
 +
</syntaxhighlight>
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">echo </font><font color="#0000bb">1 </font><font color="#007700">+ </font><font color="#0000bb">2</font><font color="#007700"><nowiki>;</nowiki><br /> if (</font><font color="#0000bb">1 </font><font color="#007700"><nowiki>== </nowiki></font><font color="#0000bb">2</font><font color="#007700">)<br /> echo </font><font color="#dd0000">'hello' </font><font color="#007700">. </font><font color="#dd0000">' world'</font><font color="#007700"><nowiki>;</nowiki><br /></font> </font> </code></div>
+
Bad:
  
<nowiki>|| and &amp;&amp; will always be used for 'or' and 'and' respectively. Resolve priority collisions with extra brackets as required.</nowiki>
+
<syntaxhighlight lang="php">
 +
// stdClass written incorrectly
 +
$a = new StdClass();
  
</div><div id="section_9">
+
// no parentheses after constructor
 +
$b = new RssBlock;
  
==== Functions and Methods ====
+
// lowercase user-created class
 +
$c = new fancyblock();
 +
</syntaxhighlight>
  
 
'''Declaration:'''
 
'''Declaration:'''
 +
<syntaxhighlight lang="php">
 +
/**
 +
* PHPDoc comment describing the function
 +
*
 +
* Note how the default value has no spaces
 +
*
 +
* @param $var type What it is for.
 +
* @param $b Class Example var that is of a specific class.
 +
*/
 +
function foo($a, Class $b, $c='') {
 +
    // source
 +
    return $value;
 +
}
 +
 +
class FooBar extends Bar {
 +
 +
    /**
 +
    * PHPDoc for the field
 +
    *
 +
    * For this project, do not use doThis.
 +
    */
 +
    public function do_this($c, $d) {
 +
        // source
 +
    }
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">/**<br /> * PHPDoc comment describing the function<br /> *<br /> * Note how the default value has no spaces<br /> */<br /></font><font color="#007700">function </font><font color="#0000bb">foo</font><font color="#007700">(</font><font color="#0000bb">$a</font><font color="#007700">, Class </font><font color="#0000bb">$b</font><font color="#007700">, </font><font color="#0000bb">$c</font><font color="#007700"><nowiki>=</nowiki></font><font color="#dd0000"><nowiki>''</nowiki></font><font color="#007700">) {<br />     </font><font color="#ff8000">// source<br />     </font><font color="#007700">return </font><font color="#0000bb">$value</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /><br /> class </font><font color="#0000bb">FooBar </font><font color="#007700">extends </font><font color="#0000bb">Bar </font><font color="#007700">{<br /><br />     </font><font color="#ff8000">/**<br />      * PHPDoc for the field<br />      *<br />      * For this project, do not use doThis.<br />      */<br />     </font><font color="#0000bb">public </font><font color="#007700">function </font><font color="#0000bb">do_this</font><font color="#007700">(</font><font color="#0000bb">$c</font><font color="#007700">, </font><font color="#0000bb">$d</font><font color="#007700">) {<br />         </font><font color="#ff8000">// source<br />     </font><font color="#007700">}<br /><br /> }<br /></font> </font> </code></div>
+
}
 +
</syntaxhighlight>
  
 
'''Calling:'''
 
'''Calling:'''
 +
<syntaxhighlight lang="php">
 +
$result = foo($bar, $baz);
 +
$mine = $object->method($a, $b);
 +
</syntaxhighlight>
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#0000bb">$result </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">foo</font><font color="#007700">(</font><font color="#0000bb">$bar</font><font color="#007700">, </font><font color="#0000bb">$baz</font><font color="#007700">);<br /></font><font color="#0000bb">$mine </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">$object</font><font color="#007700">-&gt;</font><font color="#0000bb">method</font><font color="#007700">(</font><font color="#0000bb">$a</font><font color="#007700">, </font><font color="#0000bb">$b</font><font color="#007700">);<br /><br /></font></font></code></div></div></div>
+
=Javascript=
 +
All files must adhere to the [[BasicJSFileTemplates]].
 +
Javascript files should roughly follow [http://javascript.crockford.com/code.html Crockford's code conventions].

Latest revision as of 14:07, 25 February 2022

This page documents the coding conventions used by Mahara. Everything that ends up in the git repository (other than third-party code) should follow these standards.

You can also have a look at the Reviewer's manual to see what reviewers will look at when looking at code submissions.

Separate pages with more information:


Accessibility

Mahara should be accessible to anybody. We are aiming to follow the WCAG 2.1 AA principles. There are a areas that we identified that require changes to achieve that aim. New and changed code should always be written with accessibility principles and guidelines in mind rather than tagged on 'when there is time'. Writing code accessible from the start makes it better code and requires less refactoring later on.

The style guide, accessible via 'yourmaharadomain/theme/styleguide.php', gives useful basic information for a lot of style elements.

Since the field of accessibility is changing, certain elements may require updates over time. You can find more information on our 'Accessibility' page.

File Headers

All files must adhere to the BasicPHPFileTemplates. There are slightly different templates depending on whether the script is to be included or whether it is to be directly hit.

Closing php tags ?> should be omitted.

Whitespace

Required:

  • Indentation is using four (4) spaces, not tabs.
  • Line endings should be "Unix-style" (\n), not "Windows-style" (\r\n).
  • Avoid extra whitespace at the end of modified lines.
  • Avoid editing whitespaces unrelated to your specific code change, when submitting a patch. It makes reviewing the patch more difficult and add unnecessary noise to the change history.


Recommended:

  • There is no requirement that the scripts are wrapped at 80 columns, however developers are asked to wrap long lines sensibly.

Language Constructs

switch/case statements

"case" should use multiline formatting:

switch ($var) {
    case 1:
        a = 25;
        b = 100;
        break;
    default:
        a = 0;
        b = 0;
}

NOT

case 1: a = 25; b = 100; break;

Variables and Arrays

Variables should be named with no underscores, and no capital letters. This policy may become more lenient in future if variable names are discovered that are not easily readable without underscores.

Do not name variables as negatives where possible - always use positive names and logical inversion (!) where required.

Hungarian notation is forbidden.

Aligning = signs for variable assignment is up to the developer, although they should use common sense in such decisions.

Hardcoded binary data is not allowed for security reasons.

Hardcoded serialised data is not allowed for security reasons.

Good:

$found = false;
$ponies = 0;
$servername = $overkill;

// Only in relation to controlling for/while loops
for ($i = 10; $i > 5; $i--) {
    echo $i;
}

// Aligning = signs
$mine   = 0;
$yours  = 0;
$theirs = 0;

// Only if the number of elements to initialise is small.
$array = array(1 => 'hello');

// If large number of elements to initialise:
$array = array(
    1  => 'hello',
    2  => 'goodbye',
    10 => 'erm'
);

Bad:

// Negative name
$notfound = true;
// Underscores
$my_variable = '';
// Hungarian
$count_i = 6;
// Uppercase letters
$myFish = $yourFish;

$array = array(
                1 => 'hello',
                2 => 'goodbye',
                10 => 'erm'
              );

Binary Operators

Always have a space on each side:

echo 1 + 2;
if (1 == 2)
echo 'hello' . ' world';

|| and && will always be used for or and and respectively. Resolve priority collisions with extra parentheses as required.

Classes, Functions and Methods

Nameing

Classes should start with upper case character, then each word capitalized.

class ExampleWhizbang {
    // ...
}

Leave double empty line between classes blocks in the code.

Functions should not use camel case, and instead use underscores as word separators

function do_something(){
    // ...
}

NOT

function doSomething() {
    // ...
}

Function name must start with a letter (no _ character before function name, unless you declare magic method where double underscore is used).

Leave single empty line between two function blocks and between function block and code if function is used in non-library file.

The built-in PHP class "stdClass" should be written with a lowercase s, uppercase C, because that is its actual name. Other capitalizations, such as "StdClass" will not cause an error because invocations of classnames and functions are case-insensitive in PHP. However, it is good style to use the same capitalization as the declaration of the class/function.

Constructors without arguments should be called with empty parentheses after them.

Good:

$a = new stdClass();
$b = new RssBlock();

Bad:

// stdClass written incorrectly
$a = new StdClass();

// no parentheses after constructor
$b = new RssBlock;

// lowercase user-created class
$c = new fancyblock();

Declaration:

/**
 * PHPDoc comment describing the function
 *
 * Note how the default value has no spaces
 *
 * @param $var type What it is for.
 * @param $b Class Example var that is of a specific class.
 */
function foo($a, Class $b, $c='') {
    // source
    return $value;
}

class FooBar extends Bar {

    /**
     * PHPDoc for the field
     *
     * For this project, do not use doThis.
     */
    public function do_this($c, $d) {
        // source
    }

}

Calling:

$result = foo($bar, $baz);
$mine = $object->method($a, $b);

Javascript

All files must adhere to the BasicJSFileTemplates. Javascript files should roughly follow Crockford's code conventions.