Thứ Hai, 16 tháng 6, 2014

Coding Standards [Development Best Practices]


The Drupal community has agreed that its code  base  must have a standardized look and  feel to improve readability and  make diving in easier for budding developers. Developers of contributed modules are encouraged to adopt these standards as well. Actually, let me be frank: your modules will not be taken seriously unless you follow the coding standards. I’ll cover
the standards first and  then introduce a few automated tools to help  you chec your code  (and even correct it for you!
Line Indention and  Whitespace
Drupal code  uses two spaces for indentation—not tabs.  In most editors, you can set a preference tautomatically replace
tabs  with spaces, so you can still use the Tab key to indent if you’re working against the force of habit. Lines should
have notrailing whitespace at the end. Files should be formatted with a Unix \n as the end-of-line character and  not with
the Windows standard \r\n. All text files should end  in a single newline (\n).
Operators
All binary operators, such as +, -, =, !=, ==, >, etc., should have a space before and  after the operator. For example,
an assignment should be formatted as  = a  + b instead of c=a+b. Unary operators, such as ++, should not have a space
between the operator and the variable they are operating on.
Casting
You should put a space between the (type) and  the $variable in a cast, such as (int) $count.
Control Structures
Control structures such as if, for, while, and  switch should have one space between the control keyword and  the opening
parenthesis, to distinguish them from function calls.  For example the if statement below demonstrates the correct use and  placement of opening parenthesis.
if (condition1 || condition2) { do something;
}
elseif (condition3 &&   condition4) { do something  else;}
else {
just do this;}
You are strongly encouraged to use curly braces even in situations where they are technically optional. Having  them
increases readability and  decreases the likelihood of logic errors being introduced when new lines are added. Switch
statements are formatted as demonstrated here:
switch   (condition) { case  1:
action1; break;
case  2: action2; break;
default: defaultaction;}
For do-while statements, the format is as follows:
do { actions;
} while  ($condition);
Function Calls
In function calls, there should be a single space surrounding the operator (=,  <,  >, etc.) and  no spaces between the nameof the function and  the function’s opening parenthesis. There is also no space between a function’s opening parenthesis and
its firsparameter. Middle function parameters are separated with a comma and  a space, and  the last parameter has no
space between it and  the closing parenthesis. The following examples illustrate these points:
Incorrect
$var=foo  ($bar,$baz);
Correct
$var  = foo($bar, $baz);
There’s  one exception to the rule. In a block of related assignments, more space may be inserted between assignment
operators if it promotes readability:
$a_value                 = foo($b);
$another_value   = bar();
$third_value          = baz();
Function Declarations
There should be no space between a function’s name and  its opening parenthesis. When  writing a function that uses default
values for some of its parameters, list those parameters last. Also, if your function generates any data that may be useful,
returning thadata in case the caller wants to use it is a good practice. Some function declaration examples follow:
Incorrect
function foo  ($bar  = 'baz',  $qux){
$value  = $qux + some_function($bar);
}
Correct
function foo($qux, $bar  = 'baz') {
$value  = $qux + some_function($bar); return  $value;}
Function Names
Function names in Drupal are in lowercase and  based on the name of the module or system they are
part  of. This convention avoids namespace collisions. Underscores are used to separate descriptive parts of the function
name. After the module name, the function should be named with the verb and  the object of that verb: modulename_verb_object(). In the first following example, the incorrectly named function has no module prefix, and  the verb and  its
object are reversed. The subsequent example, obviously, corrects these errors.
Incorrect
function some_text_munge()  {...}
Correct
function mymodule_munge_some_text()  {...}
Private functions follow the same conventions as other functions but are prefixed with an underscore.
Class Constructor Calls
When calling class constructors with no arguments, always include parentheses, such as the following:
$foo  = new  MyClassName();
This is to maintain consistency with constructors that have arguments:
$foo  = new  MyClassName($arg1,  $arg2);
Note that if the class name is a variable, the variable will be evaluated first to get the class name, and then the constructor will be called. An example of using  a variable as a class name is as follows:
$bar = 'MyClassName';
$foo  = new  $bar();
$foo  = new  $bar($arg1,  $arg2);
Arrays
Arrays are formatted with spaces separating each  element and  each  assignment operator. If an array block spans more than 80 characters, each  element should be moved to its own line. Its good practice to put each  element on its own line
anyway for readabilityand  maintainability. This allows you to easiladd or remove array elements.
Incorrect
$fruit['basket']  = array('apple'=>TRUE,  'orange'=>FALSE,  'banana'=>TRUE, 'peach'=>FALSE);
Correct
$fruit['basket']  = array( 'apple' => TRUE, 'orange'    => FALSE, 'banana'  => TRUE, 'peach' => FALSE,);
When  creating internal Drupal arrays, such as menu items or form definitions, always list only one element on each  line:
$form['flavors'] = array('#type'  => 'select', '#title' => t('Flavors'), '#description' =>  t('Choose a  flavor.'), '#options'=>  $flavors,);
Quotes 
Drupal does  not have a hard standard for the use of single quotes vs. double quotes. Where  possible, keep consistency
within eac module, and  respect personal styles of other developers. With that in mind, there is one caveat: single quote
strings are known tobe faster  because the parser doesn’t have to look for inline variables. Single quotes are recommended
except in the following:
1.       Inline variable usage, e.g., <h2>$header</h2>”
2.       Translated strings where one can avoid  escaping single quotes by enclosing the string  in double quotes.One such 
string would be He’s a good person.” It would be ‘He\s a good person.’ with single quotes. Such escaping may not be
properly handled by .pot file generators for text translation, and  it’s also a little awkward to read.
String Concatenators
You should always use a space between the dot and  the concatenated parts to improve readability, as in the following
example:
$string = ‘Foo’  . $bar;
$string = $bar  . ‘Foo’;
$string = bar() . ‘Foo’;
$string = ‘foo’ . ‘bar’;
When  you concatenate simple variables, you can use double quotes and  add the variable inside, such as the following example:
$string = "Foo $bar";
Comments
Drupal follows most of the Doxygen comment style guidelines. All documentation blocks  must use the following syntax:
/**
*   Documentation here.
*/
The leading spaces that appear before the asterisks (*) on lines after the first one are required.
When  documenting a function, the documentation block must immediately precede the function it documentswith no intervening
blank linesDrupal understands the Doxygen constructs in the following list; although I’ll cover the most common ones, please refer to the Doxygen site for more information on how to use them:
     @mainpage
     @file
     @defgroup
     @ingroup
     @addtogroup (as a synonym of @ingroup)
     @param
     @return
     @link
     @see
     @{
     @}
The beauty of adhering to these standards is that you can automatically generate documentation for your modules using the API
contributed module. The API module is an implementation of a subset othe Doxygen documentation generator specification, tuned
to produce output that best benefits a Drupal code  base. You can see this module in action by visiting http://api.drupal.org, and  you can learn more about the API module at http://drupal.org/project/api.
Documentation Examples
Let’s walk through the skeleton of a module from top to bottom and  highlight the different types  of documentation along  the way.Before declaring functions, take a moment to document what  the module does  using  the following format:
/**
*   @file
*   One-line  description/summary of  what your  module does  goes  here.
*
*   A  paragraph or  two in  broad strokes about  your  module and how it behaves.
*/
Documenting Constants

PHP constants should be in all capital letters, with underscores separating proper words. When  defining PHP constants, it’s a good
idea to explain what  they’re going to be used for, as shown in the following code  snippet:
/**
*   Role  ID for  authenticated users;  should  match what's  in  the  "role"  table.
*/
define('DRUPAL_AUTHENTICATED_RID',  2);
Documenting Functions
Function documentation should use the following syntax:
/**
*   Short  description, beginning   with  a  verb.
*
*   Longer description goes  here.
*
*   @param  $foo
*   A  description of  what $foo  is.
*   @param  $bar
*   A  description of  what $bar  is.
*   @return
*   A  description of  what this  function will  return.
*/
function  name_of_function($foo, $bar)  {
...
return  $baz;}
The short description should begin with an imperative verb in the present tense, such as “Munge form data or Do remote address
lookups (not “Munges form data or Does remote address lookups”). Lets take a look at an example from Drupal core that is
found within system.module:
/**
*   Add  default buttons   to  a  form and set its prefix.
*
*   @param  $form
*         An  associative array  containing the  structure of  the  form.
*
*   @return
*         The form structure.
*
*   @see system_settings_form_submit()
*   @ingroup forms
*/function  system_settings_form($form) {
...
}
There are a couple of new Doxygen constructs in the preceding example:
     @see tells you what  other functions to reference. The preceding code is a form definition, so @see points to the submit
handler for the form. When  the API module parses this to produce documentation (such as that available athttp://api.drupal.org), it will turn the function name that follows @see into a clickable link.
     @ingroup links a set of related functions together. In this example, it creates a group of functions that provide form definitions.
You can create any group name you wish. Possible core values  are: batch, database, file, format, forms, hooks, image, menu, node_access,  node_content, schema api,  search, theme able, and validation.
Functions that implement common Drupal constructs, such as hooks or form validation/ submission functions, may omit  the full
@param and @return syntax  but should still contain a one-line description of wha the function does,  as in this example:
/**
*   Validate the  book settings  form.
*
*   @see book_admin_settings()
*/
function  book_admin_settings_validate($form, &$form_state)  {
...
}
}
It is useful  to know if a function is a menu callback (that is, mapped to a URL using  hook_menu()):
/**
*   Menu  callback; prints a  listing of  all  books.
*/
function  book_render() {...}
Documenting Hook Implementations
When  a function is a hook  implementation, there is no need to document the hook.  Simply state which hook  is being implemented,as in the following example:
/**
*   Implements hook_theme().
*/
function statistics_theme(){
...}
Including Code
Any where you are unconditionally including a class file, use required_once(). Anywhere you are including a class file, use include_once(). Either  of these will ensure that class files are only included once. They share the same file list, so you don’t need tworryabout mixing  them. A file included with require_once() will not be included again by a call to include_once(). An example of using
require_once is as follows:
require_once(DRUPAL_ROOT  . '/' . variable_get('cache_inc', 'includes/cache.inc'));
PHP Code Tags
Always use <?php ?> to delimit PHP code  and  not the shorthand <? ?>. This is required for Drupal compliance anis also
the most portable way to include PHP code  on different operating systems. The ?> is always omitted from the end of a code
file; this includes modules and  include files. The reasons for this include the following:
1.       Eliminating the possibility for unwanted whitespace at the end of files, which can cause “header already sent” errors, XHTML/XML validation issues, and  other problems
2.       The closing delimiter is optional.
3.       PHP.net itself removes the closing delimiter from the end of its file, setting the best  practice.
You should, however, use the closing ?> tag when you are mixing PHP and  HTML and  there is HTML that follows
the PHP code.
Semicolons
The PHP language requires semicolons at the end  of most lines, but allows them to be omitted at the end of code  blocks.  Drupal
 coding standards require them, even at the en of code  blocks.
Example URLs
Use example.com for all example URLs per RFC 2606.
Naming Conventions
Functions and  variables should be named using lowercase, and  words should be separated by an underscore. Functions should in
addition have the grouping/module name as a prefix, to avoid name collisions between modules. Persistent variables (variables/
settings defined using Drupal’s variable_get()/variable_set()functions) should be named using all lowercase letters, an words shouldbe separated with an underscore. They should use the grouping/module name as a prefix, to avoid name collisions between
modules. Constants should always be in all uppercase, with underscores to separate words. This includes predefined PHP constants
like TRUE, FALSE, and  NULL. Module-defined constant names should also be prefixed by an uppercase spelling of the module
they are defined byGlobal variables should start with a single underscore followed by the module/theme name and another
underscore. Classes should be named using CamelCase”—for example, DatabaseConnection. Class methods and properties
should use lower CamelCase, such as $lastStatement. The use of private class methods and properties should be avoided.  You
should define classes as  protected  so that another class can extend your class and  change the method if necessary.Protected and public methods and  properties should not use an underscore prefix.All documentation files should have their file name extension set
to .txt to make viewing them on Windows systems easier. Also the file names for such files should be in all caps  (e.g., README. 
txt) while the extension itself should be in lowercase.

Checking Your Coding Style with Coder Module
At http://drupal.org/project/coder, youll find a treasure that will save you a lot of time  and aggravation. It’s the coder module: a module that reviews  the code  in other modules. To have the coder module review your module, click the new “Code review” linkin your site navigation, an selec the kind of review you want  and  the module or theme you would like to have reviewed. Or usethe handy Code Review link thatthis module provides on the list of modules.
You can even go a step  further and  use the coder_format.php  script that comes with the coder module. The script actually fixesyour code  formatting errors. Here is how to have coder_format.php check  the annotate module we wrote  in Chapter 2:
$  cd  sites/all/modules
$  php contrib/coder/scripts/coder_format/coder_format.php \ custom/annotate/annotate.module
The script modifies the file annotate.module in place  and  saves the original as annotate.module.coder.orig. To see what  the
script did, us diff:
$  diff custom/annotate/annotate.module custom/annotate/annotate.module.coder.orig
Finding Your Way Around Code with grep
grep is a Unix command that searches through files looking for lines that match a supplied regular expression. If you’re a Windows
user and  would like to follow along  with these examples, you can use grep by installing a precompiled version (see http://unxutils.sourceforge.net) or by installing the Cygwin environment (http://cygwin.com). Otherwise, you can just use the built-in search
functionality of the operating system rather than grep.
grep is a handy tool when looking for the implementation of hooks within Drupal core, finding the place  where error messages are
being built,  and  so on. Lets look at some examples of using  grep from within the Drupal root directory:
$  grep  -rl  'hook_init' .
./authorize.php
./includes/common.inc
./modules/simpletest/tests/system_test.module
./modules/simpletest/tests/theme_test.module
./modules/simpletest/tests/theme.test
./modules/simpletest/tests/actions_loop_test.module
./modules/locale/locale.module
./modules/dblog/dblog.module
./modules/update/update.module
./modules/system/system.api.php
./modules/system/system.module
./modules/overlay/overlay.install
./modules/overlay/overlay.module
./update.php
./themes/engines/phptemplate/phptemplate.engine
In the preceding case, we are recursively searching (-r) our Drupal files for instances of hook_init starting at the current directory
(.) and printing out the file names (-l) of the matching instances. Now look at this example:
$  grep  -rn  'hook_init' .
./authorize.php:31: *  avoid  various unwanted operations, such  as  hook_init() and
./includes/common.inc:2697: *  drupal_add_css() in  a  hook_init()  implementation.
./includes/common.inc:2750: *  theme .info files.  Modules that   add stylesheets  within hook_init()
./includes/common.inc:3770: *  drupal_add_css() in  a  hook_init()  implementation.
./includes/common.inc:3810: *  hook_init()  implementations, or  from other  code  that ensures   that   the
./includes/common.inc:4829:   // Initialize $_GET['q']  prior   to  invoking   hook_init().
./includes/common.inc:4835:   // Prior  to  invoking   hook_init(), initialize the  theme (potentially a custom
./includes/common.inc:4837:   // - Modules with  hook_init() implementations that   call theme()  or
./modules/simpletest/tests/system_test.module:184: *  Implements hook_init().

Here,  we are recursively searching (-r) our Drupal files for instances of the string  hook_init and printing out the actual lines and
line numbers (-n) where they occur. We could further refine  our search by piping results into another search. In the following
example, we search for occurrences of the word poll in the previous example’s search result set:
$grep  -rn  'hook_init' . | grep  'dblog'./modules/dblog/dblog.module:88: *  Implements hook_init().
Another way to refine your search is by using the -v  flag fo grep,   which means invert this match”; that is, let matches through
that do not match the string. Let’s find all the occurrences of the word lock without matching the words block  or Block:
$  grep  -rn  'lock' . | grep  -v  '[B|b]lock'
./includes/common.inc:2548: // See  if the  semaphore is still locked.
./includes/database.mysql.inc:327:function  db_lock_table($table) {
./includes/database.mysql.inc:332: *  Unlock all locked  tables.
...
Summary
After reading this chapter, you should be able to
     Code according to Drupal coding conventions.
     Document your code  so that your comments can be reused by the API module.
     Comfortably search through Drupal’s code  base  using grep.
     Identify Drupal coding ninjas by their best  practices.

Không có nhận xét nào:

Đăng nhận xét