User Tools

Site Tools


coding

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
coding [2007/08/17 09:14] fgmcoding [2010/09/17 20:13] fgm
Line 1: Line 1:
 +====== Coding conventions - standards for OSInet-originated PHP and HTML code ======
  
 +  * OSInet contributions to Drupal 
 +    * Contributions to Drupal core follow the [[http://drupal.org/node/318|Drupal coding standard]].
 +    * Contributions to non-OSInet contributed code follow the coding convention of said code, usually the same Drupal coding standard as core.
 +    * Contributions outside core follow the here-defined OSInet coding style.
 +  * Contributions to PEAR follow the [[http://pear.php.net/manual/en/standards.php|PEAR coding standards]]
 +  * Contributions to the Zend Framework follow the [[http://framework.zend.com/manual/en/coding-standard.html|Zend Framework coding style]]
 +
 +The OSInet coding style is mostly the Zend Framework style, except for its indenting rules, which follow the second variant of the [[http://en.wikipedia.org/wiki/One_True_Brace#Whitesmiths_style|Whitesmiths]] / Symbian style with spacing set to two spaces. For HTML the coding style is [[http://en.wikipedia.org/wiki/One_True_Brace#Banner_style|banner]].
 +
 +Examples on this page are given in the context of a module (Drupal) or class called G2.
 +
 +All code must work under error_reporting(E_ALL | E_STRICT)
 +
 +====== Indenting ======
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Function Declarations =====
 +
 +<html>
 +<table class="inline" style="width: 100%">
 +  <tr>
 +    <th>OSInet</th>
 +    <th>Drupal</th>
 +    <th>PEAR</th>
 +    <th>ZF</th>
 +    </tr>
 +  <tr style="white-space: pre; font-family: monospace;"><td style="vertical-align: top">private function foo($bar, $baz = 'qux'
 +  {
 +  $ret = action;
 +  return $ret;
 +  }</td><td style="vertical-align: top">function _g2_foo($bar, $baz = 'qux') {
 +  return action;
 +}</td><td colspan="2" style="vertical-align: top">private function foo($bar, $baz = 'qux')
 +    {
 +        return action;
 +    }</td>
 +      </tr>
 +    </table>
 +  </html>
 +
 +Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate. Never use parentheses around the returned value (ZF: it can break code if a method is later changed to return by reference).
 +
 +For long argument lists or long argument names, appropriate line wrapping may be used, like:
 +<code php>
 +public function someFunctionWithALongName(
 +  $firstParamsHasALongNameToo,
 +  $secondParamIsAlmostWorse   = 'default',
 +  $notForgettingOtherDefaults = 0)
 +  {
 +  $ret = action;
 +  return $ret;
 +  }
 +</code>
 +
 +
 +
 +
 +===== Class Declarations =====
 +
 +<html>
 +<table class="inline" style="width: 100%">
 +  <tr>
 +    <th>OSInet</th>
 +    <th>Drupal</th>
 +    <th>PEAR</th>
 +    <th>ZF</th>
 +    </tr>
 +  <tr style="white-space: pre; font-family: monospace;"><td style="vertical-align: top">class Foo
 +  {
 +  // members
 +  }</td><td style="vertical-align: top">N.A: no classes</td><td>?</td><td style="vertical-align: top">class Foo
 +{
 +    // members
 +}</td>
 +      </tr>
 +    </table>
 +  </html>
 +
 +
 +===== if / then / else =====
 +
 +<html>
 +<table class="inline" style="width: 100%">
 +  <tr>
 +    <th>OSInet</th>
 +    <th>Drupal</th>
 +    <th>PEAR</th>
 +    <th>ZF</th>
 +    </tr>
 +  <tr style="white-space: pre; font-family: monospace;"><td style="vertical-align: top">if (test1 || test2)
 +  {
 +  action1;
 +  }
 +elseif (test3 && test2)
 +  {
 +  action2;
 +  }
 +else 
 +  {
 +  defaultaction;
 +  }</td><td style="vertical-align: top">if (test1 || test2) {
 +  action1;
 +}
 +elseif (test3 && test4) {
 +  action2;
 +}
 +else {
 +  defaultaction;
 +}</td><td style="vertical-align: top">if ((test1) || (test2)) {
 +    action1;
 +} elseif ((test3) && (test4)) {
 +    action2;
 +} else {
 +    defaultaction;
 +}</td><td style="vertical-align: top">if (test1) {
 +    action1;
 +} else if (test3) {
 +   action2;
 +} else {
 +   defaultaction;
 +}</td></tr>
 +  <tr>
 +    <td>&nbsp;</td>
 +    <td><a href="http://drupal.org/node/318">Control structures</a></td>
 +    <td><a href="http://pear.php.net/manual/en/standards.control.php">Control structures</a></td>
 +    <td>derived from §A.4.6.1.</td>
 +  </table>
 +</html>
 +
 +Note that for ZF, the code sample supplied in the doc contradicts the doc text. Reference is made to the text. The rules and sample do not specify parenthesing for multiple tests in a clause.
 +
 +For OSInet, long tests must be wrapped to align readably. Although ZF does not mention this, the line length requirement makes it likely too.
 +
 +
 +===== switch =====
 +
 +<html>
 +<table class="inline" style="width: 100%">
 +  <tr>
 +    <th>OSInet</th>
 +    <th>Drupal</th>
 +    <th>PEAR</th>
 +    <th>ZF</th>
 +    </tr>
 +    <tr style="white-space: pre; font-family: monospace">
 +      <td style="vertical-align: top">switch (condition) 
 +  {
 +  case 1:
 +    action1;
 +    break;
 +
 +  case 2:
 +    action2;
 +    break;
 +
 +  default:
 +    defaultaction;
 +    break;
 +  }</td>
 +      <td style="vertical-align: top">switch (condition) {
 +  case 1:
 +    action1;
 +    break;
 +
 +  case 2:
 +    action2;
 +    break;
 +
 +  default:
 +    defaultaction;
 +    break;
 +}</td>
 +      <td style="vertical-align: top">switch (condition) {
 +case 1:
 +    action1;
 +    break;
 +
 +case 2:
 +    action2;
 +    break;
 +
 +default:
 +    defaultaction;
 +    break;
 +}</td>
 +      <td style="vertical-align: top">switch (condition) {
 +    case 1:
 +        break;
 +
 +    case 2:
 +        break;
 +
 +    default:
 +        break;
 +}</td>
 +    </tr>
 +  </table>
 +</html>
 +
 +
 +===== General table =====
 +
 +^ Category ^  OSInet  ^  Drupal  ^  PEAR    ^  ZF      ^
 +^ Spacing  | Control statements should have one space between the control keyword and opening parenthesis, to distinguish them from function calls. ||| Control statements based on the if and elseif constructs must have a single space before the opening parenthesis of the conditional, |
 +^ ... terminal |  n.a.                ||| ... and a single space after the closing parenthesis. |
 +^ Bracing  | always use curly braces even in situations where they are technically optional |||  n.a.  |
 +^ ... control, opening | The opening brace is written on the line below the structure. |  n.a.  || The opening brace is written on the same line as the conditional statement.  |
 +^ ... control, closing |  = ZF  |  n.a.  || The closing brace is always written on its own line.  |
 +^ ... classes |  = ZF  |  n.a.  || The brace is always written on the line underneath the class name.  |
 +
 +
 +
 +
 +
 +
 +
 +
 +====== Function Calls ======
 +
 +^ Category  ^  OSInet  ^  Drupal  ^  PEAR    ^  ZF      ^
 +^ name to ( |  no space  ||||
 +^ ( to arg1 |  no space  ||||
 +^ arg to ,  |  no space  ||||
 +^ , to arg  | usually 1 space. May vertically align for block-related function calls |  1 space  |||
 +^ arg to )  |  no space  ||||
 +^ ) to ;    |  no space  ||||
 +
 +ZF rules for this are implied by the example in the A.4.5.2 section.
 +
 +
 +====== Arrays ======
 +
 +Spacing, one-liner: **identical**
 +Spacing, indented: **Different**
 +
 +Note that if the line spans longer than 80 characters (often the case with form and menu declarations), each element should be broken into its own line, and indented one level. "=>" symbols ought to be aligned.
 +
 +<code php>
 +$form['title'] = array
 +  (
 +  '#type'        => 'textfield',
 +  '#title'       => t('Title'),
 +  '#size'        => 60,
 +  '#maxlength'   => 128,
 +  '#description' => t('The title of your node.'),
 +  );
 +</code>
 +
 +Additional comma: identical.
 +
 +====== Including Code ======
 +
 +
 +
 +OSInet contrib code does not support PHP4, so PHP5 structures like the new object model are standard.
 +
 +
 +
 +This means that including can make use of the autoload mechanism, which can be more efficient under caching than using require_once with conditional content.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +====== File formatting ======
 +
 +^ Feature      OSInet    ^  Drupal              PEAR      ^  ZF        ^
 +| <% %> tags  |  No        |  No                  ?          ?         |
 +| <? ?> tags  |  No        |  No                  ?          ?         |
 +| Closing ?>  |  No        |  Should be omitted  |  ?          No        |
 +| Indenting    2 spaces  |  2 spaces            4 spaces  |  4 spaces  |
 +| Tabs        |  No        |  No                  No        |  No        | 
 +| Line length |  as ZF      unspecified        |  ?          Strive for 80  \\  Maximum 120  |
 +| Line termination  |  \n recommended  |  unspecified  |  ?    |  \n mandatory  \\  \r and \r\n forbidden  |
 +| __HALT_COMPILER() |  unspecified  |  unspecified      ?    |  Forbidden, except in special install files  |
 +
 +The rule regarding the closing ?> tag is only applicable to "program-type" PHP files, not to HTML pages with embedded PHP, which are mostly out of the scope of these rules.
 +
 +
 +====== Comments, inline doc ======
 +
 +<html>
 +  <table class="inline">
 +    <tr>
 +      <th>Category</th>
 +      <th>OSInet</th>
 +      <th>Drupal</th>
 +      <th>PEAR</th>
 +      <th>ZF</th>
 +      </tr>
 +    <tr>
 +      <td>Documentation format</td>
 +      <td>PHPDocumentor</td>
 +      <td>Doxygen</td>
 +      <td>?</td>
 +      <td>PHPDocumentor</td>
 +      </tr>
 +    <tr>
 +      <td>File header</td>
 +      <td style="vertical-align: top; text-alignment: left; font-family: monospace">like ZF, but
 +        <ul>
 +          <li>use CeCill 2.0 license if possible</li>
 +          <li>@package and @subpackage tags to group files</li>
 +          <li>see tag to cross-refer elements</li>
 +          <li>@version tag can use other VCS' equivalents to CVS' $Id$
 +          </ul>
 +       </td>
 +      <td style="vertical-align: top; text-alignment: left; font-family: monospace">
 +        <pre>// $Id$
 +        </pre>use GPL 2.0 license for core and preferably GPL 2.0 for contrib too</td>
 +      <td style="vertical-align: top; text-alignment: left; white-space: pre; font-family: monospace">?</td>
 +      <td style="vertical-align: top; text-alignment: left; white-space: pre; font-family: monospace">/**
 + * Short description for file
 + *
 + * Long description for file (if any)...
 + *
 + * LICENSE: Some license information
 + *
 + * @copyright  2005 Zend Technologies
 + * @license    http://www.zend.com/license/3_0.txt   PHP License 3.0
 + * @version    CVS: $Id:$
 + * @link       http://dev.zend.com/package/PackageName
 + * @since      File available since Release 1.2.0
 +*/</td>
 +      </tr>
 +    <tr>
 +      <td>File header for class file</td>
 +      <td>as ZF, except @version, use $Id$</td>
 +      <td>N.A.: no classes</td>
 +      <td>?</td>
 +      <td style="vertical-align: top; text-alignment: left; white-space: pre; font-family: monospace">/**
 + * Short description for class
 + *
 + * Long description for class (if any)...
 + *
 + * @copyright  2005 Zend Technologies
 + * @license    http://www.zend.com/license/3_0.txt   PHP License 3.0
 + * @version    Release: @package_version@
 + * @link       http://dev.zend.com/package/PackageName
 + * @since      Class available since Release 1.2.0
 + * @deprecated Class deprecated in Release 2.0.0
 + */</td>
 +      </tr>
 +    <tr>
 +      <td>Function header</td>
 +      <td>as ZF</td>
 +      <td>unspecified</td>
 +      <td>?</td>
 +      <td>
 +        <ul>
 +          <li>Textual description</li>
 +          <li>all @param</li>
 +          <li>@return</li>
 +          <li>@throws if the function throws an exception</li>
 +          <li>@access now obsoleted by visibility attributes</li>
 +          </ul>
 +        </td>
 +    </table>
 +  </html> 
 +
 +
 +
 +====== Using CVS ======
 +
 +
 +
 +**Identical**
 +
 +
 +
 +Additional rule: modules must define a constant containing the version information to be displayed on the module settings page. See the rules for constants below.
 +
 +
 +
 +====== Example URLs ====== 
 +
 +
 +
 +**Identical**
 +
 +
 +
 +
 +
 +====== Naming Conventions ======
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== General =====
 +
 +<html>
 +  <table class="inline" style="width: 100%">
 +    <col span="5" align="left" />
 +    <tr>
 +      <th>Element</th>
 +      <th>OSInet</th>
 +      <th>Drupal</th>
 +      <th>PEAR</th>
 +      <th>ZF</th>
 +      </tr>
 +    <tr style="vertical-align: top">
 +      <td>Functions</td>
 +      <td>as ZF</td>
 +      <td style="font-family: monospace">g2_get_element_by_id()</td>
 +      <td style="font-family: monospace">?</td>
 +      <td style="font-family: monospace">getElementById()</td>
 +      </tr>
 +    <tr style="vertical-align: top">
 +      <td>Function scope</td>
 +      <td>as ZF</td>
 +      <td>No classes, so use "&lt;module_name&gt;_" as a namespace to avoid name collision</td>
 +      <td>?</td>
 +      <td>Floating functions are discouraged. Use a static class.</td>
 +      </tr>
 +    <tr style="vertical-align: top">
 +      <td>Accessors</td>
 +      <td>as ZF</td>
 +      <td>N.A.: no classes</td>
 +      <td>?</td>
 +      <td style="font-family: monospace">getSomeField<br />setSomeField</td>
 +      </tr>
 +    <tr style="vertical-align: top">
 +      <td>Design patterns</td>
 +      <td>as ZF</td>
 +      <td>unspecified</td>
 +      <td>?</td>
 +      <td>Include name of pattern in the name of the method, where practical</td>
 +      </tr>
 +    <tr>
 +      <td>Constants</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">class G2
 +  {
 +  const SOME_CONSTANT = 'foo';
 +  }</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">define('G2_SOME_CONSTANT', 'foo');</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">?</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">class G2 {
 +  const SOME_CONSTANT = 'foo';
 +}</td>
 +      </tr>
 +    <tr>
 +      <td>Class fields</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">private   _someFieldOne;
 +protected _someFieldTwo;
 +public    someFieldThree;</td>
 +      <td style="vertical-align: top">PHP4 pseudo-private field: _some_field</td>
 +      <td style="vertical-align: top">?</td>
 +      <td style="white-space: pre; font-family: monospace; vertical-align: top">private _someFieldOne;
 +protected _someFieldTwo;
 +public someFieldThree;</td>
 +      </tr>
 +    <tr>
 +      <td>Global variables</td>
 +      <td>no specific rule</td>
 +      <td>_g2_some_variable</td>
 +      <td>?</td>
 +      <td>no specific rule</td>
 +      </tr>
 +    <tr>
 +      <td>Code files</td>
 +      <td style="vertical-align: top">
 +        <ul>
 +          <li>Drupal components: as Drupal</li>
 +          <li>elsewhere: as ZF</li>
 +          </ul>
 +        </td>
 +      <td style="vertical-align: top">
 +        <ul>
 +          <li>Module: .module</li>
 +          <li>Module install: .install</li>
 +          <li>Themes:
 +            <ul>
 +              <li>Plain PHP: .theme</li>
 +              <li>PHPTemplate: .tpl.php</li>
 +              </ul>
 +            </li>
 +          <li>Includes: .inc</li>
 +          </ul>
 +        </td>
 +      <td style="vertical-align: top">?</td>
 +      <td style="vertical-align: top">
 +        <ul>
 +          <li>all files containing PHP code must bear the .php extension</li>
 +          <li>the file containing class Foo must be named Foo.php</td>
 +          </ul>
 +        </td>
 +      </tr>
 +    <tr>
 +      <td>Documentation</td>
 +      <td style="vertical-align: top">
 +        <ul>
 +          <li>Standard files: LICENSE.txt</li>
 +          <li>Specific files:
 +            <ul>
 +              <li>CamelCaps.txt</li>
 +              <li>Allowed text formats:
 +                <ul>
 +                  <li>txt (UTF8)</li>
 +                  <li>PDF</li>
 +                  <li>OpenDocument</li>
 +                  </ul>
 +                </li>
 +              <li>Allowed image formats:
 +                <ul>
 +                  <li>SVG, SVGZ</li>
 +                  <li>PNG, including Fireworks</li>
 +                  <li>JPG</li>
 +                  </ul>
 +                </li>
 +              </ul>
 +            </li>
 +          </ul>
 +        </td>
 +      <td style="vertical-align: top">LICENSE.txt</td>
 +      <td style="vertical-align: top">?</td>
 +      <td style="vertical-align: top">?</td>
 +      </tr>
 +    </table>
 +  </html>
 +
 +
 +===== Variables =====
 +
 +Variables naming following the rules for functions and methods. Exceptions:
 +
 +  * existing libraries or APIs are not renamed. Facade APIs may be used until existing libraries match the new format
 +  * the standard variable $ret should be used for all return values. Always use it to return a value, instead of directly returning the latest instruction result. This helps with a typical debugger configuration: breakpoint on return and $ret as a watched value.
 +  * some Hungarian notation is used: 
 +    * the name of "unsafe" strings is prefixed by "us_"
 +    * http://www.joelonsoftware.com/articles/Wrong.html
 +  * naming resulting from external objects applies the rule by pieces. Example:
 +    * GTK widgets are named <abbreviated class><Instance> within Glade
 +    * GTK signals are called <signal>
 +    * Related callbacks are called on_<abbreviated class><Instance>_<signal>
 +    * Example: on_fmMain_destroy is 
 +      * "on_" : the callback for...
 +      * "fmMain" : a Main Form GtkWindow widget
 +      * "_destroy" : the "destroy" GTK signal
 +    * Rationale: forcing CamelCaps for the standard naming convention would result in onFmMainDestroy, which splits ambiguously and is not a default in Glade, and with Fm being capitalized inconsistently in various places in the app. As an instance instead of a class, it should remain lowercase
 +
 +
 +===== Functions and Methods =====
 +
 +  * Since PHP4 support is not required, visibility (private, protected) settings on class members are recommended when using PHP5 class constructions.
 +  * functions or methods returning unsafe values are prefixed by "us_" just like variables, as "us_someFunctionName()"
 +  * "final" classes should not contain "protected" members, since they can not have derived classes which would take advantage of the "protected" access.
 +
 +
 +===== Constants =====
 +
 +As of 01/01/2007, see table above. Note that the PHP builtins "null", "true", and "false" are lowercase, unlike constants from user code.
 +
 +Previously, the format was:
 +<code php>
 +define('G2VERSION', '$Id');
 +</code>
 +
 +This style of coding is now considered obsolete (even under Drupal conventions, the constant should be named G2_VERSION, not G2VERSION), and should be replaced when preparing module versions for Drupal 6 by class constants like G2::VERSION, or more generally Foo::SOME_CONSTANT :
 +
 +<code php>
 +class G2
 +  {
 +  // don't forget the PHPdoc here
 +  const VERSION = '$Id$';
 +  }
 +</code>
 +
 +
 +===== Drupal-specific: Naming functions and constants within modules =====
 +
 +  * Drupal mandates some function names, notably, for module "mymodule":
 +    * default theme functions must be named theme_mymodule_foo 
 +    * hook_foo implementations must be named mymodule_foo
 +  * Beyond that, all other functions in a module should be defined as static public methods of a class named like the module, like:
 +<code php>
 +// don't forget the PHPdoc comments here
 +class My_Module
 +  {
 +  // and here
 +  const SOME_CONSTANT = 'bar';
 +
 +  // ... and here too
 +  static public function foo($op)
 +    {
 +    // do something and return
 +    }
 +  }
 +
 +// ..which can be invoked as:
 +My_Module::foo(My_Module::SOME_CONSTANT);
 +</code>
coding.txt · Last modified: 2020/11/23 17:23 by 127.0.0.1