Last updated April 3, 2014. Created by Crell on October 19, 2009.
Edited by vivekvpandya, scor, jhodgdon, vijaycs85. Log in to edit this page.

Drupal follows common PHP conventions for object-oriented code, and established industry best practices. As always, though, there are Drupal-specific considerations.

Class-related coding standards covered elsewhere

Contents of this page

Indenting and Whitespace

Please refer Indenting section for basic indenting that are applicable in OO as well. Here is few additional that are specific to OO.

Leave an empty line between start of class/interface definition and property/method definition:

<?php
class GarfieldTheCat implements FelineInterface {
 
// leave empty line here
 
public function meow() {
...
...
...
?>

Leave an empty line between end of property definition and start method definition:

<?php
...
...
...
  protected
$lasagnaEaten = 0;
 
// leave empty line here
 
public function meow() {
    return
t('Meow!');
  }
?>

Leave an empty line between end of method and end of class definition:

<?php
class GarfieldTheCat implements FelineInterface {
...
...
...
  public function
eatLasagna($amount) {
   
$this->lasagnaEaten += $amount;
  }
 
// leave empty line here
}
?>

Naming conventions

  1. Classes and interfaces should use UpperCamel naming.
  2. Methods and class properties should use lowerCamel naming.
  3. If an acronym is used in a class or method name, make it CamelCase too (SampleXmlClass, not SampleXMLClass). [Note: this standard was adopted in March 2013, reversing the previous standard.]
  4. Classes should not use underscores in class names unless absolutely necessary to derive names inherited class names dynamically. That is quite rare, especially as Drupal does not mandate a class-file naming match.
  5. Names should not include "Drupal".
  6. Class names should not have "Class" in the name.
  7. Interfaces should always have the suffix "Interface".
  8. Test classes should always have the suffix "Test".
  9. Protected or private properties and methods should not use an underscore prefix.
  10. Classes and interfaces should have names that stand alone to tell what they do without having to refer to the namespace, read well, and are as short as possible without losing functionality information or leading to ambiguity. Notes:
    • If necessary for clarity or to prevent ambiguity, include the last component of the namespace in the name.
    • Exception for Drupal 8.x: due to the way database classes are loaded, do not include the database engine name (MySQL, etc.) in engine-specific database class names.
    • Exception for test classes: Test classes only need to be unambiguous within the context of the module they are testing.

Stand-alone name examples:

Namespace Good name Bad names
Drupal\Core\Database\Query\ QueryCondition Condition (ambiguous)
DatabaseQueryCondition (Database doesn't add to understanding)
Drupal\Core\FileTransfer\ LocalFileTransfer Local (ambiguous)
Drupal\Core\Cache\ CacheDatabaseDriver Database (ambiguous/misleading)
DatabaseDriver (ambiguous/misleading)
Drupal\entity\ Entity
EntityInterface
DrupalEntity (unnecessary words)
EntityClass (unnecessary words)
Drupal\comment\Tests\ ThreadingTest CommentThreadingTest (only needs to be unambiguous in comment context)
Threading (not ending in Test)

A complete example of class/interface/method names:

<?php
interface FelineInterface {
  public function
meow();
  public function
eatLasagna($amount);
}
class
GarfieldTheCat implements FelineInterface {
  protected
$lasagnaEaten = 0;
  public function
meow() {
    return
t('Meow!');
  }
  public function
eatLasagna($amount) {
   
$this->lasagnaEaten += $amount;
  }
}
?>

Use of interfaces

The use of a separate interface definition from an implementing class is strongly encouraged because it allows more flexibility in extending code later. A separate interface definition also neatly centralizes documentation making it easier to read. All interfaces should be fully documented according to established documentation standards.

If there is even a remote possibility of a class being swapped out for another implementation at some point in the future, split the method definitions off into a formal Interface. A class that is intended to be extended must always provide an Interface that other classes can implement rather than forcing them to extend the base class.

Use an .inc file and use files[] in the .info.yml file to extend a class or implement an interface.

If you include a file that extends a class or implements an interface, PHP generates a fatal error if the parent class or interface is not loaded. So, if a class is provided by a contributed module, or core in some cases, it is not safe to put your classes in a .module file. It's better to use an .inc file and use files[] in your .info.yml file. For example, even if you have a dependency on a module, it's possible that both your module and the dependency are disabled when your .module file is included. Since the registry won't auto-load a class from a disabled module, this would cause an error. Also, when hook_boot() is run, module dependencies aren't loaded. So, if you add a class, then later implement hook_boot(), your module could be loaded without the dependency, and that will also generate a fatal error. Using an .inc file and using files[] in your .info.yml file is needed to avoid those errors.

Visibility

All methods and properties of classes must specify their visibility: public, protected, or private. The PHP 4-style "var" declaration must not be used.

The use of public properties is strongly discouraged, as it allows for unwanted side effects. It also exposes implementation-specific details, which in turn makes swapping out a class for another implementation (one of the key reasons to use objects) much harder. Properties should be considered internal to a class.

Type hinting

PHP supports optional type specification for function and method parameters for classes and arrays. Although called "type hinting" it does make a type required, as passing an object that does not conform to that type will result in a fatal error.

  • DO specify a type when conformity to a specific interface is an assumption made by the function or method. Specifying the required interface makes debugging easier as passing in a bad value will give a more useful error message.
  • DO NOT use a class as the type in type hinting. If specifying a type, always specify an Interface. That allows other developers to provide their own implementations if necessary without modifying existing code.

Example:

<?php
// Wrong:
function make_cat_speak(GarfieldTheCat $cat) {
  print
$cat->meow();
}
// Correct:
function make_cat_speak(FelineInterface $cat) {
  print
$cat->meow();
}
?>

Instantiation

Creating classes directly is discouraged. Instead, use a factory function that creates the appropriate object and returns it. This provides two benefits:

  1. It provides a layer of indirection, as the function may be written to return a different object (with the same interface) in different circumstances as appropriate.
  2. PHP does not allow class constructors to be chained, but does allow the return value from a function or method to be chained.

Chaining

PHP allows objects returned from functions and methods to be "chained", that is, a method on the returned object may be called immediately, like so:

<?php
// Unchained version
$result = db_query("SELECT title FROM {node} WHERE nid = :nid", array(':nid' => 42));
$title = $result->fetchField();
// Chained version
$title = db_query("SELECT title FROM {node} WHERE nid = :nid", array(':nid' => 42))->fetchField();
?>

As a general rule, a method should return $this, and thus be chainable, in any case where there is no other logical return value. Common examples are those methods that set some state or property on the object. It is better in those cases to return $this rather than TRUE/FALSE or NULL.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

What should be the name of the file which contains only one single class?
Lets say we have an interface "FelineInterface" should I put in into a file FelineInterface .inc or
somethin like that ?Is there any rule for that ?

--
Regards,
Robert

DO NOT specify a type for a class. If specifying a type, always specify an Interface.

This should be removed; Type hint is a step towards type-safe code: it's better to have a crash where the error is instead of experiencing all sorts of warnings and unexpected behavior multiple layers lower or upper: it makes errors being evident and easier to find. Type hinting, whatever it is with array, interfaces or class names is always a good idea and should be advised to use everywhere it can.
PHP is not type safe per essence, but we can use type hinting to make some critical portions of code to be closer to type safe: it is a really bad advice to discourage people from using type hinting in general.

That allows other developers to provide their own implementations if necessary without modifying existing code.

That is under the assumption the original code is meant to be extended: this is not always the case. Plus it doesn't prevent people from extending by inheritance. Letting people pass anything wrong is making the whole framework fragile and unstable. If you want the code to be flexible and extensible, you have to design it for: type hinting has nothing to do with flexibility.

I think that this suggests that you should have an interface for the class and that you use the interface rather than the concrete class as the type hint.

The interface is the contract that binds any sub-class / alternative class to the correct behavior, so that your function / method should still work no matter what is being passed in.

If it is really mission critical that the class / behavior of a method can not be changed in any shape or form (never seen this myself in any OOP coding before), use a final class or an abstract base class with final keywords on the required methods rather than an interface.


Alan Davison
Back roads somewhere in South America

Hi,
nice to have this page, but..
should it not be mentioned that this is specifically for D8?
With a link to the D7 conventions.. (which I did never like, but who cares)

None of this is specific to Drupal and follows de facto standards for writing OO-style PHP code. And you're right, no one cares!