version: #8 (current)  |  last edited by: Mischa Kroon  |  on: thursday, september 16, 2010, 3:03 am pdt (about 8 years ago)


Qcodo Coding Standards

Source code is for humans to read, and only incidentally for machines to run.
--Donald Knuth, Professor Emeritus of Computer Science, Stanford University

Introduction

This document details out the coding standards for the Qcodo Development Framework.  The coding standards defined includes the guiding principles for source code structure, formatting conventions and naming standards.

While this document details out the standards and conventions used for the classes and objects for the Qcodo core, there is obviously no requirement that these standards need to be followed for any application built on top of Qcodo.  This is of course one of the great benefits of Open Source software development.

However, in order to make code easier to read and much easier to maintain, it is strongly encouraged that these conventions be adopted for any application that uses Qcodo.

The only caveat is for applications that utilize multiple frameworks, with each having its own strongly adhered-to coding standards (e.g. the Zend Framework, PEAR and Qcodo all have their own strongly-followed coding standards, with each standard being significantly different than the others).  For applications that take this blended approach to integrating with multiple frameworks, the exercise is left to the lead engineer or technical architect to come up with a set of coding standards which would be suitable for the application or project team.

One recommendation would be to consider adopting the standard of the “main” or most-utilized framework, and borrowing the standards from the other frameworks whenever the code is specifically dealing with classes or objects from that framework.  A typical example would be an application that mostly uses the Qcodo stack for data objects (e.g. the code generator), but uses Zend_Form for front-end development.  In that case, custom business logic/functionality and data classes would be written in the Qcodo coding standard, while the front-end forms that utilize Zend_Form would utilize the ZF coding standard.  And finally, if a third framework is used on occasion (for example, a custom application class is written to extend from PEAR::Image_Barcode), then the PEAR coding standard should be used for the custom functionality written in that custom class.

How to Use This Document

For developers that adding, editing or maintaining core functionality to Qcodo itself, this document should be used as is.  The standards described below should be adhered to as closely as possible.  If coding or design situations arise where this document is not clear or is ambiguous, the developer should bring it to the attention of the Qcodo Framework maintainers so that a clear standard can be articulated and shared among the rest of the Qcodo community of developers.

For project teams that are developing applications that use Qcodo (either exclusively, or in conjunction with other frameworks), it should be up to the Architect or Technical Lead of the project to determine how much of this document should be practiced on the project team.

Regardless of how much this particular document is followed, it is strongly recommended that all project teams follow at least some set of clearly documented standards which are practiced by all developers on the team.

Files

Architecturally, it is not necessarily advantageous to dictate a file/folder hierarchy for all applications.  Each application is unique in its needs and nuances, and thus, the definition of a file/folder structure and hierarchy must be flexible to suit those needs.

Qcodo, itself, does try to maintain a standard structure for itself, and has a loose recommendation of a structure could be followed for Qcodo-based projects:

  • cli/ - to store the Qcodo Command Line Interface (CLI) runner and application-based CLI scripts
  • database/ - to store any create, data and update SQL scripts, as well as any source ER diagramming files, PDFs of data model, data model-based documentation, data dictionary and definitions, etc.
  • design/ - any design-level documentation should reside in this folder, including screen wireframes, visual comps, “cut” HTML files, etc.
  • documentation/ - any other documentation goes here (e.g. PDFs and Word DOCs explaining technical specifications, presentations on project vision, etc.)
  • includes/ - the main includes directory or classfiles library for the application.  qcodo/ should be a main subdirectory in the includes/ directory, and qcodo/_core/ contains the core of the Qcodo framework
  • tests/ - the test suite and test scripts for the Qcodo application should reside here
  • www/ - any web-accessible file, including web-executable PHP files, javascript files, CSS, static HTML files, etc. should reside in this directory.  Therefore, www/index.php can be run in a browser by going to http://www.mydomain.com/index.php

Any PHP-based file should end in .php as a standard as well as for security reasons.  Files should have a secondary suffix if it is not a top-level (e.g. web-executable) PHP script.

  • view_project.php - any top-level web-executable PHP file (e.g. a PHP file that is intended to actually be called in the browser) would simply have a “.php” suffix with no secondary suffix.  Note that the file name is all lower-case and underscore-spaced.
  • ExampleClassDefinition.class.php - any class file, whether it is a QControl-based class, a data class, or any other custom class defintion, should have the name of the class followed by “.class.php” as its filename.  Note that the class name is Pascal Cased (see below for more information).  The only exception to this is a QForm definition that is actually run by the file (e.g. MyForm::Run() is called on the page), in which case, this file is now considered a top-level web-executable file (see above).
  • SaveDialogBox.tpl.php - any PHP file that is intended to be a template to a custom QControl should be the name of the class of the custom QControl followed by “.tpl.php”.  Again, note that the class name is pascal cased.  The template file should reside in the same directory as the custom QControl class that it is a template for.
  • pnlDisplayName.tpl.php - any PHP file that is intended to be a template for a specific instance of a QControl in a single QForm should be the instance name followed by “.tpl.php”.  Note that the instance name followed prefixed pascal Casing.  These files should typically reside in the same directory as the top-level web-excutable PHP QForm file.
  • admin_header.inc.php - any PHP file that is truly just an “include” file for standardized HTML (e.g. headers and footers) should be lower-cased and underscore-spaced followed by “.inc.php”
  • process-emails.cli.php - any command line interface script (especially if run by the Qcodo CLI Runner) should be lower-cased and hyphen-spaced and followed by “.cli.php”.  These files should typically reside in cli/scripts as well.

Formatting Conventions

Spacing and Identing

Code should be properly indented using hard tabs set to 4-spaces per tab.  Any switch in internal context (e.g. starting PHP, a function definition, a code block for an if statement, etc.) should be indented one tab from its parent context.  Open braces should appear in the same line that declares the new context.  For example:

<?php
    
function FooBar($intCount) {
        
$intValue 15;
        
$strFooBar 'This is a test.';
        
        for (
$intIndex 0$intIndex $intCount$intIndex++) {
            print 
$intValue ' - ' $strFoorBar;
            print 
"\r\n";
        }

        
$intValue $intValue 25;
    }
?>

Long lines can also be cut shorter by indenting a single tab as well:

<?php
    $objMyObject 
SomeClass::QueryArray(QQ::AndCondition(
        
QQ::Equal(QQN::SomeClass()->FirstName'John'),
        
QQ::Equal(QQN::SomeClass()->LastName'Smith'),
        
QQ::Equal(QQN::SomeClass()->Age25)));
?>

If and if/else statements should mostly follow similar rules, with the exception that AND and OR based conditional statements can be indented with an extra space (or extra spaces) to allow conditioanl statements to horizontally line up for easier readability:

<?php
    
if ((strlen($strData) > 20) ||
        ((
$strFoo == $strBlah) &&
         (
$intValue 15))) {
        
$strMyOtherValue 'blah';
        
SomeFunction($strMyOtherValue);
        
$intValue++;
    }
?>

Finally, please note that these indent rules will become significantly looser on HTML-embedded PHP pages (e.g. template files and includes).  Indenting should be attempted as often as possible for child-DOM objects, and PHP indenting rules should follow suit.

For longer PHP code blocks, the PHP start (“<?php”) and PHP end (“?>”) tags should reside on its own line and should be unindented.

However, for single-line PHP code blocks, the PHP start and end tag could reside on the same line as long as it obeys the current indent level:

<html>
    <body>
        <h2>Welcome Page</h2>
        
        <div class="foo">
<?php
            $strData 
$_GET['foo'];
            
$strData str_replace(10$strData);
            if (
$strData) {
?>
                The quick brown fox jumps over the lazy dog.<br/>
                <img src="/foobar.png"/><br/>
                This is neat!
<?php
            
}
?>

            Additional content in this div goes here.
            <ul>
                <li>One</li>
                <li>Two</li>
                <li>Three</li>
            </ul>

            <?php if (array_key_exists('flag'$_GET)) { ?>
                You have selected the <strong>flag</strong>.
                <img src="/flag.png"/><br/>
            <?php ?>
        </div>
    </body>
</html>

Commenting

PHPDoc style DocBlock comments should be declared on all functions, methods and classes.  For PHP files that are not class files (e.g. includes, etc.) where a class-based DocBlock does not make sense, then a file-based DocBlock should be declared at the top of the file.

Single-line inline code comments can use c++-style “//” comments as long as they share the indent level as the code being commented:

<?php
    
// Validate the user
    
$blnResult QApplication::Authenticate($objUser);

    if (!
$blnResult) {
        
// The user was not valid
        
QApplication::Redirect('/login/');
    } else {
        
// Record the user's login
        
$objUser->RecordLoginTime(QDateTime::Now());
    }
?>

For multi-line comments, c-style “/*” and “*/” comments are acceptable as well (as long as they obey the indent level of the code being commented).

Naming Standards

Pascal Case

A large majority of the Qcodo naming convention calls for “Pascal Case” notation, or some variant of pascal casing.  Pascal Case notation only calls for alphanumeric characters (no spaces, hyphens, underscores, or any other punctuation marks).  It is a mixed-case notation, with capital letters signifying the start of a new word for multi-word terms.  Also, note that abbreviations should be treated as a word, and therefore should not be set in all-caps.  Examples of Pascal Case names:

  • Example
  • ThisIsAnotherExample
  • GetAddressForUrl
  • PushToHttpServer

Note that even for abbreviations such as URL and HTTP, they are listed as Url and Http in the above names.

Non OO Standards

Because Qcodo is a completely object-oriented framework, this document offers little guidance on functions and global variables that reside outside of any object context.

In general, it is strongly recommended that all globally used functions be defined as static methods in the QApplication class.  However, because of performance and code formatting reasons, this is not always possible.  For example, Qcodo has a small handful of functions that perform print-based operations which can be called globally.  These functions have names that start with the underscore character (“_“) and are named by one or two letters (e.g. the _p() function for general printing).  But outside of these special cases, it's recommended that developers avoid designing applications which require the use functions that reside outside any object scope.

The same can be said for global variables.  The only special cases are with QForms and QControls, which have three special global variables that are set by the QForm handler, itself:

  • $_FORM
  • $_CONTROL
  • $_ITEM

More will be added to this list as time goes on, but the variable names will always start with the underscore character (“_“) and be in all caps.

Outside of these special cases, it is strongly recommended that developers avoid the use of global variables.  Avoiding its use will greatly increase code maintainability and greatly decrease coding mistakes and the time to fix bugs.

Constants

Constants in PHP applications can generally be divided into two different types of constants: application settings and enumerations.

Application settings are things like server settings, locations of resources (databases, filesystem, etc.) and other server- and application-specific values which can be changed on occasion with new server deployments, or as the physical architecture of the application changes.

In general, they should be defined in the configuration.inc.php file, and should be underscore-spaced and in all caps, for example “LIKE_THIS”.  Moreover, constants that specifically deal with directory locations should be prefixed and suffixed with two underscore characters, for example “_INCLUDES _” and “_DOCROOT _”.

Enumerations are programming constructs to apply an arbitrary integer value to real world values.  An example of this from a Project Management tool would be Project Statuses (which could be “Active”, “Pending”, “Cancelled”, “Completed”, “About to start”, etc.).  Enumerations are used to bring coding consistency and improve performance for these values: comparing integer values are significantly faster than comparing string values, and integer comparisons like this are significantly less prone to typing errors and typo-related bugs.

Enumeration-based constants should always be defined as class constants.  They can either be defined within the class which uses those values, or within a separate abstract class whose sole purpose is to store enumerated constants.  So using the above example, the enumerated values for project status could be defined as constants either in the Project class, or a new abstract ProjectStatus class could be defined to store the constants.  Constant names should be in camal-case format, and should always start with a single capital letter.  So given the above example, the constants would be defined in PHP as:

    abstract class ProjectStatus {
        const Active = 1;
        const Pending = 2;
        const Cancelled = 3;
        const Completed = 4;
        const AboutToStart = 5;
    }

As a reminder, note that the actual integer values are completely arbitrary.  There is no requirement to have the values “flow” in any sort of order or to have any sort of rules behind them.

Classes

Qcodo has standardized on Pascal Case notation as names for classes, and should always begin with a capital letter.  There is no set rule on special naming constructs for abstract versus concrete classes or on subclasses.  There are a few Qcodo-specific standards which are used:

  • Any Qcodo-based class (e.g. classes that are part of the core Qcodo distribution) are prefixed with a single “Q”, e.g. QControl, QApplication, etc.
  • Any Qcodo code-generated class which are subclassed and intended to not be edited are prefixed with a “Gen”.  E.g. for most data classes for an example project management application, you will have a Project class and a ProjectGen class, where the Project class inherits from ProjectGen.
  • Any core Qcodo class which is subclassed by a non-core Qcodo class should be suffixed with a “Base”.  Remember that both core and non-core Qcodo classes are classes that are part of the Qcodo distribution.  The main difference is that “core” Qcodo classes are not necessarily meant to be altered/edited by application developers, while “non-core” Qcodo classes were specifically designed to be altered/edited/extended by application developers.  The best example of this would be QFormBase and QForm, where QFormBase is a core class which isn't intended to be modified, and QForm inherits from QFormBase and is specifically intended to be modified.
  • Any Qcodo code-generated “Type” class should have “Type” as a suffix.  Combined with the “Gen” constant, the name would be like ProjectTypeGen (which is inherited by ProjectType).

Class Methods

Class methods should be in Pascal Case notation and should always begin with a capital letter.

One exception to this rule is event handlers as methods in QForm and QControl classes.  Those methods should typically be the variable instance name, followed by an underscore (“_“) and the event being handled.  So for example, for a method that is meant to be a “Click” event handler on a textbox named txtName, the event handler method should be “txtName_Click”.

The other exception to this rule is for the Form-based event handling methods in QForm, itself:

  • Form_Create
  • Form_Load
  • Form_Validate
  • Form_Run
  • etc.

(Note that actually these two exceptions both refer to the same style of method naming even though they deal with different sets of classes (QControls for the former, QForm for the latter).  Either way, they deal with an event handler or a delegate-based method call on an object.)

There are no special naming conventions for virtual or static methods, and there are no special naming conventions based on the protection level of any given method (e.g. public vs. protected vs. private).

Class Member Variables (non-static)

Class member variables (which are non-static) should follow a prefixed Pascal Case notation.  The prefix should always be three lower-cased letters, and should signify what the type of the variable is:

  • $strFirstName
  • $intRowCount
  • $objProject

There are some standard three-letter prefixes which can be used:

  • bln - boolean
  • dtt - QDateTime
  • flt - float / single / double
  • int - integer
  • str - string
  • frm - QForm
  • btn - QButton
  • cbl - QCheckBoxList
  • chk - QCheckBox
  • col - QDataGridColumn
  • dlg - QDialogBox
  • dtg - QDataGrid
  • dtr - QDataRepeater
  • lbl - QLabel
  • lst - QListBox
  • pnl - QPanel
  • rad - QRadioButton
  • rbl - QRadioButtonList
  • txt - QTextBox
  • ctl - any other custom control
  • obj - any other object (data classes, etc.)

Class Properties and Static Class Member Variables

Class properties, as well as static class member variables, should be in Pascal Case notation.  Note that there should not be a prefix (unlike the case for non-static class member variables).

Also, there are no special naming constructs for abstract vs. concrete, or for protection level.

Text Strings

Text strings should use single-apostrophe unless the text string contains a lot of single-apostrophes (e.g. if the text string is a SQL statement):

<?php
    $strText 
'Hello, world!';
    
$strHtml '<div id="someDiv" class="pullQuote">This is some content</div>';
    
$strSqlStatement "SELECT * FROM my_table WHERE first_name LIKE 'John%';";
?>

Implicit variable lookups should not be allowed.  Use the dot-operator for concatenation instead.  For text strings that concatenate multiple strings and variables together, sprintf() might be a cleaner approach:

<?php
    
// NOT Recommended
    
$strBadString "Hello, my name is $strFirstName $strLastName and today is $strDate.";

    
// Do either of these instead
    
$strBetterString 'Hello, my name is ' $strFirstName ' ' $strLastName ' and today is ' $strDate;

    
$strBest sprintf('Hello, my name is %s %s and today is %s',
        
$strFirstName$strLastName$strDate);
?>

Miscellaneous

  • Full PHP-start tags should be used (“<?php”) instead of “short” tags (“<?”)
  • PHP Print shortcut (“<?=“) should never be used.
  • Commands like print and echo should never be used when not in cli context.  Use _p() instead.
  • eval() should be avoided at all costs
  • backtick operators (“`”) should be avoided as well.  Use PHP methods like exec() instead.
  • PHP code files should have no leading or tailing whitespace.  The php start tag should be the very first item in the file and the php end tag should be the very last item in the file.
  • Always explicitly provide a PHP end tag.
  • Never use ASP-style start and end tags to start and end PHP.

Please feel free and post in the comments for this Wiki page or to alter the contents of this wiki page with any changes, corrections, additions, etc.



Copyright © 2005 - 2019, Quasidea Development, LLC
This open-source framework for PHP is released under the terms of The MIT License.