akbkhome

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.
  • 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.
    • Static method calls to classes are strongly discouraged
      • instantate the object at the start of the page, and use that throughout.
    • Classes should not use prototypes constructors, rather the constructor should list the linked functions
      • linked functions should all be prefixed with the class name, and use lowercase for method name.
        function MyClass() 
        {
        /* list variables first */
        this.somevar = 1;

        /* list method second */
        this.someMethod = MyClass_someMethod;
        }

        function MyClass_someMethod ()
        {
        ....
    • Code should, in general, follow pear standards (re indentation etc.)
      • File Naming should match class names, and Heiricachy pattern.
        eg. MyProject_MyTree goes in images/js/MyProject/MyTree.js
    • Global variables
      • should be prefixed with classes that they apply to
      • not used outside the file they are defined.
      • and avoided as much as possible.
        MyClass_SOMEGLOBAL = 1;
    • Use of errors / strings that may need translation should be avoided
      • Add hidden tags into the page, so that the template engine can do the translation, then use getElementById() to fetch the contents, and render messages using this.

  • Class names should follow PEAR standards, and be verbose.
    • eg. Q3 is bad, Quiz_Type3 is good.
    • 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 = load js file, then run x = new TheObject([init variables here]);
  • For AJAX transactions with PHP use the phpRequest.js library, send POST/GET requests, and expect JSON in return.
  • Use the PEAR package Services_JSON package to generate JSON. 
  • avoid using eval(), unless interpreting JSON return values. - use try {} catch  {} on code that may fail.

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)

  • Prefer CSS over Tables (or keep table usage to a minium)
    • 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, us oncommand with javascript call.

CSS

  • Should not in general be embeded into HTML file.
  • 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

Add a comment (requires javascript!)

Name
Email
Homepage
Comment
 

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