Project Coding Standards

These are general notes applied to Projects that I work on, the main intent is to try and make the code maintainable over a long period of time.

PHP Code

  • Follow PEAR Standards Which are (with slight additions):
    • Indenting
      • 4 spaces (Not tabs)
      • Do not over indent
      • Try and keep within 80 chars wide
        Bad:
        $ret = $this->callSomething(array('xxx' => 'yyyy',
                                          'zzz' => 'aaaa' ....
        
              
        Good
        $ret = $this->callSomething(array(
              'xxx' => 'yyyy',
              'zzz' => 'aaaa' ....
        ));
              
    • Control Structures
      • If / else
        • No short ifs (eg. always use brackets)
        • do not use else if you have returned or used break; within a block.
          if ((condition) || (condition2)) {
              statement;
              statement;
          } else { 
              statement;
          }
          
          if ((condition) || (condition2)) {
              statement;
              statement;
          } elseif  ((condition) || (condition2)) { 
              statement;
          }
          
          // for long if statements
          if ((condition) 
                  || (condition2)    //8 space indent  
                  || (condition2)
                  || (condition2)
              ) {       // closer and opener 4 space indented
              statement;
              statement;
          }
          
          
          
        • break out or return rather than nesting if statements
          When inside methods or loops, use return or break, rather than have heavily nested if blocks
          for ($i = 0; $i < 100; $i++) {
              if (!$x) {
                  break;
              }
              if ($x < 10) {
          	statement;
          	statement;
                  break;
              }
              ......
          }
          
          
          function get($arg) 
          {
               $do = DB_DataObject:;factory('xxxx');
               if (!(int)$arg || !$do->get($arg)) {
                    return HTML_FlexyFramework::factory('Error/404', array('errors'=> .....);
               }
               .....
                    
          • BAD:
            function get($arg) 
            {
                 $do = DB_DataObject:;factory('xxxx');
                 if ($arg != "") {
                     if ($do->get("id",$arg)) {
                          ... do stuff ...
                     }
                 }
            }
                        
      • Switch Case 
        • indent once for case, and once for statements
        • extra line after break; except on last one.
          switch ($x) {
              case 1:
                  statement;
                  break;
              
              case 2:
                  statement;
                  break;
          
              default:
                  statement;
                  break;
          } 

      • Method Calls
        • No space between method name and ( and first paramenter
        • space after each,
        • avoid more than 2 arguments to a method (use named arguments)
        • dont over indent arguments
        • commas after argument, not before
        • extra space can be added before return assignment to enhance readability

          $ret = $this->callSomething($a, $b);
          
          $ret = $this->callSomething(array(
                      'xxx' => 'yyyy',
                      'zzz' => 'aaaa',
                 ));
          
          $abcdefg = $this->find();
          $xxx     = $this->fetch();
                   
      • Method Definitions
        • first { is on line after definition
        • return from method sooner rather than later

          function callSomething($a, $b)
          { 
              if ($a) {
                  return false;
              }
              statement;
              
          }
          
        • return should not use () brackets around return values
      • Class Definitions
        • first { is on line after definition
          class myclass extends anotherclass
          { 
              function .......()
              {
              }
              
          }
                    



    • Comments
      • Method / Class header Comments use /* */ style comments
      • Class Properties can use docbook comments or // comment after the defintion
        class something
        { 
            var $fred;  // this is fred's var
        }
        
        Longer comments should use /* */ style docbook comments

      • Methods (unless FlexyFramework get()/post()/getAuth()) require standard phpdoc comment definitons (detailing arguments) preferably with simple examples of usage.
      • Comments inside of Methods should use // style comments to enable commenting out blocks of code for debugging using /* */ style comments
          • # bash/perl style comments should not be used.
    • Include  / Require
      • include / require_once etc. should not use ( ) around arguments
      • do not attempt to cope with require_once failing (by hiding it or testing include path) 
        include 'MyClass.php
      • Always use full relative path rather than short path
        require_once 'MyProject/MyClass.php';
        //rather than
        require_once 'MyClass.php'
        
        
        
    • PHP Code tags
      • Do not use short tags (<?)
      • Do not add the closing tag to files (?>) as it often can break sessions

    • Naming Conventions
        • Classes
          • use Caps_First with _ between names. (exceptions may occur when part of the name relates to an extenal object - eg. a database table)
              • Good: Some_MyProject, Some_Project_Driver
              • Bad: SomeProjectThatWorks, SomeProject_ProjectDriver
          • Underscore  heirachy should relate to extends pattern where feasible
              • Fred_Driver extends Fred
              • Fred_Driver_Postgres extends Fred_Driver
          • Libraries should always use a type prefix (eg. HTML_/Net_/DB_ etc.)
          • Projects should always have a non-generic name, and all classes should extend that (see later)
        • Functions
          • DO NOT USE!
        • Methods / Variables
          • Always use studlyCaps with first letter lower, and latter ones upper case.
              • Good: someMethod(), $this->someVar;
              • Bad: some_method(), SomeMethod(),  $this->some_var
          • Prefix private methods with underscore (these may use _ in names as well.
            • _my_private_method()
            • $this->_my_private_var;
          • Avoid pass-by-reference, unless absolutely necessary.
        • Constants
          • Built in constants should use lower case
            • eg. true, false, null
          • User Defined constants should be associated with a class and all uppercase
            • eg. MYPROJECT_TESTFLAG
        • Global Variables
          • Should always be associated with a class
          • Should not be accessed from outside the owning class.
          • Should be initialized when the class is loaded (in global space)
    • File Formats
      • Should use UNIX line endings (\n) not (\r\n)

  • Class inheritance
    • Avoid to many levels of extends, in general code (above 3 should be extremely rare, and well justified.)

  • Require / Lazy loading
    • Utilize Lazy loading, avoid requiring files at the start of each class/page file.
    • Avoid long lists of require_once's at the top of each file.
    • Avoid assuming that a class is loaded, help the end user out by explicitly saying where some class comes from.

  • Mixing PHP + HTML/Data
    • Avoid embedding large quantities of data in PHP code. Use XML/INI or simple text files if possible
    • Avoid where possible echo'ing HTML  or text from within classes. Always prefer adding to the Templates any HTML
      • Exceptions may occur when dealing with HTML/XML Trees.
      • Only use "echo", not "print" (as this makes checking for xss vectors simpler)
    • Avoid placing validation messages in the PHP code, (This excludes system failure type messages), as this makes doing translated templates with user error messages easier.

      use
      $this->warning['messagename']= true;
      
      and in the HTML:
      
      <p flexy:if="warning[messagename]">Display the warning / error</p>
  • Method Arguments
    • Maximum of 3, over that, use named arguments array.
    • Prefered Max is 2 arguments.
    • Avoid pass by reference, unless absolutely necessary (it makes code more difficult to follow) - return arrays or associative arrays.
  • XML / HTML
      • unless processing huge XML files, use the DOM extensions rather than XML_Tree/XML_Parser.

  • DataObjects:
    • reusable chunks of  database specific code should go in the DataObjects.
      • Favour moving joinAdd constructs into the DataObject for reuse later or optimization, by manually modifying the $this->_joinAdd variable.
    • DataObjects should be initialized using DB_DataObject::factory(....)
    • DataObjects should not make direct use of input variables (eg. $_REQUEST/$_POST/$_GET etc.)
    • For frequenctly called gets/fetchs, consider defining a cachedGet() method, rather than using the staticGet provided.
    • return value for $do->get() can be considered to be boolean, and tests should look like this:
      if(!$do->get($id)) {
          $this->error = ....
          return HTML_FlexyFramework::run('Error/404');
      }
            
    • $do->get(), can work out the primary key, so do not use it with $do->get('id',$arg);
    • use $do->find(true) when fetch a single result, (rather than using $do->find() / $do->fetch();
    • user $do->escape($data) on all data going to whereAdd() or similar methods, where the data can not be trusted (eg. user input/reading from a file.)


  • FlexyFramework
    • Implement and use Page base classes
      • A project one (non-authenticated) eg. MyProject extends HTML_FlexyFramework2_Page
      • A authenticated one, eg. MyProject_Authenticated extends MyProject
    • Page Classes should avoid deep directory trees:
      • MyProject_Products_Search_Edit (MyProject/Products/Search/Edit.php) == BAD
      • MyProject_ProductsEdit (MyProject/ProductEdit.php) == GOOD.
    • Page Constructors
      • __construct or class constructors should not be used (it makes the code to difficult to follow)
    • Unused shared base classes (eg. MyProject_SomePage extends MyProject_SomePageBase)
      • Avoid these, merge the code into an existing class (either the project one or a relivant page)
    • Avoid calling parent::get() or parent::post(), make explicite methods for actions, and call them specificily in child classes. (This enables top level get/post to return 404 errors on pages not found)
    • Do not use the modules toolkit - it was a bad idea, and is only ther for Backwards compatibility
      (you should write your own project based loadModules routine, that loads any modules you intend to use)
    • Do not make error handling a module Errors should be handled with flags (or values with context data, not messages) and be part of the page template

  • Emailing
    • Should use standard Email template code, and not hard code Email into PHP. (see Flexy tricks)
    • Be careful of data injection in to Email templates
      From: { t.someemail } <test@xyz>
      Subject: A test
      .....
            
      In the above example ensure that { t.someemail } does not have line breaks comming from user input!

  • Errors
    • Do not use @ to suppress errors unless absolutly necessary.
    • in PHP4
      • use PEAR::raiseError(), lazy loaded.
      • consider outputtting debuging information via trigger_error(E_USER_WARNING) (when debugging is turned on.)
    • in PHP5,
      • trigger_errror() is for programming errors / debug warnings.
      • Exceptions for everything else (Probably PEAR_Exceptions)
        • Try and catch all exceptions where they are thrown. - try and avoid global catchalls.
        • use function arguments to determine if Exceptions should be converted to return values, or run
          HTML_FlexyFramework::run('error',array('errors'=> array('problem_with_xxx'=>true)));

  • Constants
    • Should not be used as configuration variables
    • Normal usage should be to assist in the readability of code, normally in cases where a set of numerical states can be represented by a textural word (eg. SMTP_STATE_READY_TO_SEND = 1)
    • Naming should follow PEAR standards (eg. with class name prefixed - or in PHP5 just use class constants.)

  • Configuration
    • Most configuration is automatically detected by the Framework, however other configuration settings may originate from
      • bootstrap (index.php) hard coded into the Framework constructor
      • bootstrap (index.php) may choose to load a .ini fire to help building the constructor
      • FlexyFramework's ConfigDir is depreciated.
      • If you do use configuration files, load them in the bootloader, and pass them as an argument to the HTML_FlexyFramework::factory() startup, eg.
        $siteconfig = parse_ini_file('/etc/flexyframework/myproject_config.ini');
        HTML_FlexyFramework::factory(array(
        	......
        	MyProject => $siteconfig,
        ));
                
    • Read Access
      • Global configuration is available by:
        $opts = PEAR::getStaticProperty("classname","options");
      • DO NOT write or alter the global configuration.

  • Sessions
    • All sessions should be stored associated with the class they are used in, and try not to access them directly from outside the class.. eg,
      class MyProject_TestPage extends MyProject 
      {
      
           function get()
           { 
               $_SESSION['MyProject_TestPage']['settings'] = .......
      	

  • Debugging
    • at present the recommendation is to use a debug flag on a class, and trigger_error with E_USER_WARNING. this can be caught by the error handler if neccessary and reformated.

Javascript

  • all js files go in [templatedirectory]/images/js/
    • This enables the Flexy url-rewriter to fix src locations.
    • Pman Project specific 
      • Files go in module directory, filename matches class name eg. Pman.Tab.XXX goes in Pman.Tab.XXX.js
      • At present Filename/Classnames start with Pman.Tab.* or Pman.Dialog.* depending on what the class deals with
      • Library components still go in images/js/ - usually are extensions of a Roo element.

  • functions should only be used on the page that they are called.
    • Therefore, no functions should appear in .js files

  • Included js files should be classes.
    • Classes are of three types
      • Static classes Eg. for layouts or Dialogs (less so now)
      • Implementations of Roo.Observable, created as follows
        Pman.Dialog.XXX = new Roo.Observable({ 
             xxx : function () { .... },
             yyy : 1
        });
      • Classes which can be extended - these should use Roo.extend() syntax and have a constructor.
    • Code should, in general, follow pear standards (re indentation etc.)
    • Global variables
      • should be avoided where possible - Tie a global resorce to a static class, or class instance
    • Strings
      • Use single Quotes for non-translatable strings
      • Use double Quotes for strings that require translation

  • Class names should use the Project(eg. Pman), Type(eg. Dialog),  Module name (eg. Builder), then the specific name
    • eg. Pman.Dialog.BuilderDatabaseModelView
    • names like Q3, ERM are bad, BuilderQuizType3 is better
    • Avoid generic Class names, eg. 'Util',
  • Should assume availablity of baseURL and rootURL will be provided by
    <flexy:toJavascript baseURL="baseURL" rootURL="rootURL"/>
  • Javascript included .js files should avoid running code directly, they should be initiated manually by the page.
    • BAD = .js file that modifies the whole layout when it loads
    • GOOD = registering modules with Pman, or implementing the Roo.Document.on('load', ... event)
  • For AJAX transactions with PHP use the Roo.Ajax.request(), or Pman.request()
  • (PHP/Pman project) Use the the method $this->jdata(), $this->jok(), $this->jerr() to send back data
  • avoid using eval(), unless absolutely no good alternative exits (see. Roo.decode())


General Coding (PHP / js)

  • Avoid mapping names (especially databases columns to other names)
    • BAD :  this.tbx0 = document.getElementById('username');
    • GOOD : this.username = document.getElementById('username');
    • EVEN BETTER this.elements['username'] = document.getElementById('username');
      • This can then be automated by for[each] loops...



HTML (and Flexy Templates)

  • Indent Code with 2 spaces
  • Try and keep to less than 80 characers per line
  • Layout Tags 1 per line etc.
    • Example:
      <div>
        <table>
          <tr>
            <td>XXXX</td>
          </tr>
        </table>
      </div>
            
  • Prefer CSS over Tables (or keep table usage to a minium) - use class="xxxx" rather that id="xxx" to enable reuse of styles
    • except when really representing tabular information.
  • Generally Avoid usage of absolute positioning of CSS.
    • (this can get messy when reflowing with javascript)
  • Use { baseURL } and { rootURL } in links / post locations
  • Use  the images/ folder for images, so the Template engine can rewrite the url.
  • Break complex pages into two templates and duplicate HTML rather than conditionally displaying large chunks,
    eg. BAD:
    { if:step1 } 
    .........
    { end: }
    { if:step2 } 
    .....
    { end: }
    ........
        

XUL

  • do not use commandset/command, use oncommand with javascript call.

CSS

  • Should not in general be embeded into HTML file.
  • Author / Copyright should be at top of file once, not in multiple places
  • Do not use non-english characters in comments.
  • should be located in [templatedir]/images/css/ and referenced by href="images/css/....." so the url can be rewritten by the template engine.
  • should be indented as follows
    .stylename
    {
    		display: block;
    		font-color: red;
    }
    Note the large indentation on the definitions.
  • Should be split into seperate files depending on their purpose (eg. leftnav.css / topnav.css etc.)
  • Should be carefull when redefining standard HTML elements, it is prefered to use a base style, and refer to subelements: eg.
    .mybody h2 
  • Should generally avoid using #id - prefer classes

Add a comment (requires javascript!)

Name
Email
Homepage
Comment
 

Edit Document | Create Page:
Contact me at alan@akbkhome.com