mirror of
https://github.com/e107inc/e107.git
synced 2025-08-16 03:24:20 +02:00
Created Coding Standard (markdown)
277
Coding-Standard.md
Normal file
277
Coding-Standard.md
Normal file
@@ -0,0 +1,277 @@
|
||||
IMPORTANT: This is a work in progress!
|
||||
|
||||
|
||||
# Section 1 - Pear Standard
|
||||
|
||||
(Where no comment here, the Pear standard applies unmodified) The Pear coding standards (http://pear.php.net/manual/en/standards.php) form the basis of our own standard. This standard makes some comments on those standards, and in some cases defines a different way of doing things.
|
||||
Indenting
|
||||
|
||||
Use tabs to indent - not spaces - then you can adjust your editor to suit.
|
||||
Control Structures
|
||||
|
||||
Use BSD/Allman/Pascal style - opening '{' on a new line. The only exception is for short single statements within {...} such as ' return ; '- then it may be on a single line. This is optional.
|
||||
|
||||
Good:
|
||||
|
||||
if($t ==2)
|
||||
{
|
||||
(tab)echo "hello";
|
||||
}
|
||||
|
||||
|
||||
if($t == 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if($t == 2) { return; } // (Optional -for short lines only)
|
||||
|
||||
Bad:
|
||||
|
||||
if($t ==2) echo "hello"; // Missing braces { }
|
||||
|
||||
|
||||
if($t ==2){ echo "<div>My long line of code and ".LAN_XXX." etc</div>"; }
|
||||
|
||||
## Comments and Documentation
|
||||
|
||||
Routines are to be documented at both file and function level using phpDoc syntax. Where appropriate create supplementary pages of general documentation, and document individual variables.
|
||||
Headers
|
||||
|
||||
Every file must have one or two standard headers, as defined in Stadard headers page
|
||||
Error Handling
|
||||
|
||||
At some point we will start using exceptions (*** TODO - DEFINE BETTER ***)
|
||||
Naming
|
||||
|
||||
Basically as the standard:
|
||||
camelCase for variables
|
||||
UPPER_CASE_WITH_UNDERSCORES for constants
|
||||
|
||||
$camelCase = "value";
|
||||
define("UPPERCASE_CONSTANT","value");
|
||||
|
||||
|
||||
## Section 2 - PHP/e107
|
||||
### Language Files and LANS
|
||||
|
||||
Avoid duplicating terms, particularly in the admin area. If coding for admin, always search lan_admin.php and the lan_xxxx.php of the specific page you are working on for existing LANs which may match what you need translated. Avoid using HTML or Urls inside LAN definitions.
|
||||
|
||||
Good:
|
||||
|
||||
define("LAN_XXX","Thank you [b]Firstname[/b]");
|
||||
define("LAN_XXX","Thank you [x]"); // Good - replace [ and ] with <a href='...'> and </a> using str_replace()
|
||||
|
||||
|
||||
Bad:
|
||||
|
||||
define("LAN_XXX","Thank you <b>Firstname</b>"); //Bad contains HTML
|
||||
define("LAN_XXX","Thank you <a href='www.somewhere.com'>Firstname</a>"); //Bad contains HTML
|
||||
define("LAN_XXX","Thank you [link=www.somewhere.com]Firstname[/link]"); //Bad - allows translator to modify link.
|
||||
|
||||
Avoid short language strings for words such as 'and', 'to' and so on. There aren't always equivalents in other languages. If embedding values into a phrase, use substitution. Avoid using substitution terms which are real words or known bbcodes.
|
||||
|
||||
define('LAN_EXAMPLE_01','Update results: [x] records changed, [y] errors, [z] not changed');
|
||||
$srch = array('[x]','[y]','[z]');
|
||||
$repl = array($changed,$errors,$unchanged);
|
||||
$text = str_replace($srch,$repl,LAN_EXAMPLE_01);
|
||||
|
||||
|
||||
### Programming detail
|
||||
Important: Some of these points related to form elements are deprecated in v2. Instead you should use the new form handler. `$frm->text()`, `$frm->selectbox()` etc. eg. input tags, select boxes etc.
|
||||
|
||||
1. Where numeric values represent a particular status, define a constant for that value to make the meaning more obvious.
|
||||
|
||||
define("CONSTANT","some value");
|
||||
|
||||
2. Use double-quotes around html strings, unless the variable substitution capabilities or escape sequences are required (slightly faster).
|
||||
|
||||
|
||||
echo "<input type='hidden' name='example' value='1' />";
|
||||
echo "<input type='text' name='example2' value='".LAN_XXX."' />"; //BAD - LANs may contain single-quotes.
|
||||
echo "<input type='text' name='example2' value=\"".LAN_XXX."\" />"; //GOOD - single-quote safe.
|
||||
|
||||
|
||||
3. Within text strings enclosed in double quotes, use {...} round substituted variables (clearer, avoids variable names being misconstrued)
|
||||
|
||||
echo "<input type='hidden' name='example' value='{$value}' />";
|
||||
|
||||
4. Avoid the use of global variables, especially as an alternative to parameter passing. (We'll always need some globals - but the less there are, the smaller the chance of a clash). In v2.0 use the e107::getxxx syntax to get pointers to 'global' functions and objects like $sql, $tp
|
||||
|
||||
$pref = e107::getPref();
|
||||
$sql = e107::getDb();
|
||||
|
||||
5. When passing more than three or so parameters to a function, consider passing some of them in an array (especially convenient if many are optional) or if within a class, consider using vars.
|
||||
|
||||
6. Consider switch statements rather than multiple if...then...elseif.... (generally for three or more, or better yet, use an array to change the result where possible.
|
||||
Simple 'If/Else' example:
|
||||
|
||||
if($j == 3)
|
||||
{
|
||||
$text = "Hello";
|
||||
}
|
||||
else
|
||||
{
|
||||
$text = "Goodbye";
|
||||
}
|
||||
Switch Example:
|
||||
|
||||
|
||||
switch($option)
|
||||
{
|
||||
case 'opt1':
|
||||
$val = "value1";
|
||||
break;
|
||||
|
||||
case 'opt2':
|
||||
$val = "value2";
|
||||
break;
|
||||
|
||||
case 'opt3':
|
||||
$val = "value3";
|
||||
break;
|
||||
|
||||
case 'opt4':
|
||||
$val = "value4";
|
||||
break;
|
||||
}
|
||||
|
||||
Preferred version of above:
|
||||
|
||||
$array = array(
|
||||
'opt1'=>'value1',
|
||||
'opt2'=>'value2',
|
||||
'opt3'=>'value3',
|
||||
'opt4'=>'value4'
|
||||
);
|
||||
$val = $array[$option];
|
||||
|
||||
|
||||
7. Group functions related to a particular area of e107 into a class, and place the resultant file into the e_HANDLER directory. Where there are 'admin' and 'user' functions, create an 'admin' class which is a descendant of the 'user' class to minimize memory usage in user mode. If the class contains admin functions only, either define the class within the admin file, or create a separate file within the admin directory. Before committing ANY new class/handler files to svn, be sure to check with the head developer of e107.
|
||||
|
||||
8. Don't use extract() on arrays (usually DB rows) - causes confusion, and sometimes unneeded variables. And especially don't use it on $_POST and $_GET variables!
|
||||
|
||||
Good:
|
||||
|
||||
while($row = $sql->db_Fetch(MYSQL_ASSOC)
|
||||
{
|
||||
$text .= $row['field_name'];
|
||||
}
|
||||
|
||||
Bad:
|
||||
|
||||
while($row = $sql->db_Fetch(MYSQL_ASSOC)
|
||||
{
|
||||
extract($row);
|
||||
$text .= $field_name;
|
||||
}
|
||||
|
||||
9. As $_POST variables are checked/sanitized, create new variables to hold the checked values - makes it obvious what's safe and what's dodgy. (Note validator_class.php, especially where the same DB data can be input from several different places). Make sure $_POST variables are only processed if the user has the relevant permissions, and if the relevant options are enabled (its not enough to hide the button or field which initiates the post - security levels MUST be checked at the point of execution).
|
||||
|
||||
10. Validate generated HTML on each page you work on.
|
||||
|
||||
11. Code must not produce any PHP warnings or notices during normal use. (This primarily implies that all variables must be defined before being used. It also implies that a corrupted installation may produce errors, although as far as practicable the code should accommodate this.
|
||||
|
||||
12. Where a feature is upgraded or changed:
|
||||
|
||||
For simple changes, the code should silently handle the situation
|
||||
For more complex changes, an upgrade routine is required
|
||||
|
||||
13. Use the e_XXX path constants to refer to directories:
|
||||
|
||||
Absolute constants (e_XXX_ABS) for paths within HTML pages
|
||||
Relative paths (e_XXX) to access files from within the code
|
||||
|
||||
Note SITEURLBASE to prepend to absolute links to get a full URL. Note SERVERBASE (2.0 only) to prepend to absolute links to get a full server filesystem reference
|
||||
|
||||
14. To check whether a particular plugin is installed, use function e107::isInstalled($plugname) - returns TRUE if plugin installed. Alternatively, look at $pref['plug_installed'][plug_path'] ('plug_path' is the subdirectory name - e.g. calendar_menu). The array element exists only if the plugin is installed (assuming proper install/uninstall process followed), and contains the version number of the plugin.
|
||||
|
||||
15. Use the following method when dealing with pre-selection of OPTIONs within SELECT tags.
|
||||
|
||||
$frm->selectbox($name,$array);
|
||||
|
||||
16. Where an appropriate handler exists, use it in preference to replicating or bypassing its functionality. eg. One example - use the file-class instead of PHP file functions to read directories.
|
||||
|
||||
$fl = e107::getFile();
|
||||
$files = $fl->get_files($path, $fmask);
|
||||
|
||||
### SQL Details
|
||||
|
||||
1. Don't enclose integer values in quotes in WHERE clauses - slows up the query. (But make sure there's no way the value can be something other than an integer).
|
||||
|
||||
$sql->select('user','*',"user_id = '".$id."' LIMIT 1");
|
||||
$id = 1;
|
||||
$sql->db_Select_gen("SELECT * FROM `#user` WHERE user_id = '".$id."' LIMIT 1"); //BAD - Slower and risk of failure.
|
||||
$sql->db_Select_gen("SELECT * FROM `#user` WHERE user_id = ".intval($id)." LIMIT 1"); //GOOD - Faster, 0 if no value
|
||||
|
||||
2. Where only one record is expected, use "LIMIT 1" in the query for better performance.
|
||||
|
||||
3. insert() and update() Associate field names and values (rather than using an ordered list of just values) - avoids problems with DB changes. Make sure values are specified for any field without a default - else fails in STRICT mode.
|
||||
Insert Example:
|
||||
|
||||
$insert = array(
|
||||
'user_id' => 1,
|
||||
'user_email' => 'user@email.com'
|
||||
);
|
||||
|
||||
$sql->insert($insert);
|
||||
|
||||
Update Example (many fields):
|
||||
|
||||
|
||||
$update = array(
|
||||
'user_email' => 'user@email.com',
|
||||
// ... Long list of fields/values
|
||||
'WHERE' > 'user_id = 1'
|
||||
);
|
||||
$sql->update($update);
|
||||
|
||||
Update Example (few fields):
|
||||
|
||||
$sql->update("user","user_email = 'user@email.com' WHERE user_id = 1 LIMIT 1");
|
||||
|
||||
Note the _FIELD_DEFS and _NOTNULL arrays for assisting with producing valid data. These are auto-generated for any db_Insert() or db_Update() that passes array data which does not include them. If the automatic generation produces the wrong conversions, there is a mechanism to override the default.
|
||||
|
||||
4. Use backticks around table names and field names. (eg.`#user`)
|
||||
|
||||
$sql->gen("SELECT user_email FROM `#user` WHERE user_id = 1 LIMIT 1");
|
||||
|
||||
5. Only read the fields that are actually needed, especially on tables with a large record size.
|
||||
|
||||
6. From v2.0 onwards, where the minimum required mySQL is now 4.1, the following functions are available through gen():
|
||||
|
||||
SQL_CALC_FOUND_ROWS - returns total number of rows which would match the search criteria in the absence of a LIMIT phrase.
|
||||
If used, value is automatically retrieved and placed into $sql->total_results
|
||||
REPLACE - effectively if row exists, delete it, then insert (so unspecified fields become the default)
|
||||
INSERT ... ON DUPLICATE KEY UPDATE - on existing records, will only update specified fields
|
||||
|
||||
7. To avoid problems when 'STRICT' mode is set for MySQL, make sure any field which doesn't have a default value is defined (usually 'text' fields). (This is handled automatically if passing array data to insert() or update(). (db_Insert() or db_Update())
|
||||
|
||||
8. If reading XML files (typically plugin.xml) use the filter capability to limit the amount of data retained in memory to that which is actually needed.
|
||||
|
||||
9. Consider using list() instead of explode() when the values will be given their own strings and the size of the array is known.
|
||||
|
||||
Okay:
|
||||
|
||||
$tmp = explode("|",$array);
|
||||
$id = $tmp[0];
|
||||
$email = $tmp[1];
|
||||
|
||||
Better:
|
||||
|
||||
list($id,$email) = explode("|",$array);
|
||||
|
||||
### Template Files
|
||||
|
||||
(TODO v2.0 template standards)
|
||||
|
||||
|
||||
1. Avoid code, especially functions, in template files
|
||||
|
||||
|
||||
### Shortcodes
|
||||
|
||||
1. Note and use the class-based structure introduced in v2.0 - with this it should be possible to totally avoid globals.
|
||||
|
||||
2. Parameter standards (see eHelper::scParams() and eHelper::scDualParams() )
|
Reference in New Issue
Block a user