Coding Standards

CakePHP developers will use the PSR-2 coding style guide in addition to the following rules ascoding standards.

It is recommended that others developing CakeIngredients follow the samestandards.

You can use the CakePHP Code Sniffer to check that your codefollows required standards.

Adding New Features

No new features should be added, without having their own tests – whichshould be passed before committing them to the repository.

IDE Setup

Please make sure your IDE is set up to “trim right” on whitespaces.There should be no trailing spaces per line.

Most modern IDEs also support an .editorconfig file. The CakePHP appskeleton ships with it by default. It already contains best practise defaults.

We recommend to use the IdeHelper plugin if youwant to maximize IDE compatibility. It will assist to keep the annotations up-to-date which will makethe IDE fully understand how all classes work together and provides better type-hinting and auto-completion.

Indentation

Four spaces will be used for indentation.

So, indentation should look like this:

  1. // base level
  2. // level 1
  3. // level 2
  4. // level 1
  5. // base level

Or:

  1. $booleanVariable = true;
  2. $stringVariable = 'moose';
  3. if ($booleanVariable) {
  4. echo 'Boolean value is true';
  5. if ($stringVariable === 'moose') {
  6. echo 'We have encountered a moose';
  7. }
  8. }

In cases where you’re using a multi-line function call use the followingguidelines:

  • Opening parenthesis of a multi-line function call must be the last content onthe line.
  • Only one argument is allowed per line in a multi-line function call.
  • Closing parenthesis of a multi-line function call must be on a line by itself.

As an example, instead of using the following formatting:

  1. $matches = array_intersect_key($this->_listeners,
  2. array_flip(preg_grep($matchPattern,
  3. array_keys($this->_listeners), 0)));

Use this instead:

  1. $matches = array_intersect_key(
  2. $this->_listeners,
  3. array_flip(
  4. preg_grep($matchPattern, array_keys($this->_listeners), 0)
  5. )
  6. );

Line Length

It is recommended to keep lines at approximately 100 characters long for bettercode readability. A limit of 80 or 120 characters makes it necessary todistribute complex logic or expressions by function, as well as give functionsand objects shorter, more expressive names. Lines must not belonger than 120 characters.

In short:

  • 100 characters is the soft limit.
  • 120 characters is the hard limit.

Control Structures

Control structures are for example “if”, “for”, “foreach”,“while”, “switch” etc. Below, an example with “if”:

  1. if ((expr_1) || (expr_2)) {
  2. // action_1;
  3. } elseif (!(expr_3) && (expr_4)) {
  4. // action_2;
  5. } else {
  6. // default_action;
  7. }
  • In the control structures there should be 1 (one) space before the firstparenthesis and 1 (one) space between the last parenthesis and the openingbracket.
  • Always use curly brackets in control structures, even if they are not needed.They increase the readability of the code, and they give you fewer logicalerrors.
  • Opening curly brackets should be placed on the same line as the controlstructure. Closing curly brackets should be placed on new lines, and theyshould have same indentation level as the control structure. The statementincluded in curly brackets should begin on a new line, and code containedwithin it should gain a new level of indentation.
  • Inline assignments should not be used inside of the control structures.
  1. // wrong = no brackets, badly placed statement
  2. if (expr) statement;
  3.  
  4. // wrong = no brackets
  5. if (expr)
  6. statement;
  7.  
  8. // good
  9. if (expr) {
  10. statement;
  11. }
  12.  
  13. // wrong = inline assignment
  14. if ($variable = Class::function()) {
  15. statement;
  16. }
  17.  
  18. // good
  19. $variable = Class::function();
  20. if ($variable) {
  21. statement;
  22. }

Ternary Operator

Ternary operators are permissible when the entire ternary operation fits on oneline. Longer ternaries should be split into if else statements. Ternaryoperators should not ever be nested. Optionally parentheses can be used aroundthe condition check of the ternary for clarity:

  1. // Good, simple and readable
  2. $variable = isset($options['variable']) ? $options['variable'] : true;
  3.  
  4. // Nested ternaries are bad
  5. $variable = isset($options['variable']) ? isset($options['othervar']) ? true : false : false;

Template Files

In template files developers should use keyword control structures.Keyword control structures are easier to read in complex template files. Controlstructures can either be contained in a larger PHP block, or in separate PHPtags:

  1. <?php
  2. if ($isAdmin):
  3. echo '<p>You are the admin user.</p>';
  4. endif;
  5. ?>
  6. <p>The following is also acceptable:</p>
  7. <?php if ($isAdmin): ?>
  8. <p>You are the admin user.</p>
  9. <?php endif; ?>

Comparison

Always try to be as strict as possible. If a non-strict test is deliberate itmight be wise to comment it as such to avoid confusing it for a mistake.

For testing if a variable is null, it is recommended to use a strict check:

  1. if ($value === null) {
  2. // ...
  3. }

The value to check against should be placed on the right side:

  1. // not recommended
  2. if (null === $this->foo()) {
  3. // ...
  4. }
  5.  
  6. // recommended
  7. if ($this->foo() === null) {
  8. // ...
  9. }

Function Calls

Functions should be called without space between function’s name and startingparenthesis. There should be one space between every parameter of a functioncall:

  1. $var = foo($bar, $bar2, $bar3);

As you can see above there should be one space on both sides of equals sign (=).

Method Definition

Example of a method definition:

  1. public function someFunction($arg1, $arg2 = '')
  2. {
  3. if (expr) {
  4. statement;
  5. }
  6.  
  7. return $var;
  8. }

Parameters with a default value, should be placed last in function definition.Try to make your functions return something, at least true or false, soit can be determined whether the function call was successful:

  1. public function connection($dns, $persistent = false)
  2. {
  3. if (is_array($dns)) {
  4. $dnsInfo = $dns;
  5. } else {
  6. $dnsInfo = BD::parseDNS($dns);
  7. }
  8.  
  9. if (!($dnsInfo) || !($dnsInfo['phpType'])) {
  10. return $this->addError();
  11. }
  12.  
  13. return true;
  14. }

There are spaces on both side of the equals sign.

Bail Early

Try to avoid unnecessary nesting by bailing early:

  1. public function run(array $data)
  2. {
  3. ...
  4. if (!$success) {
  5. return false;
  6. }
  7.  
  8. ...
  9. }
  10.  
  11. public function check(array $data)
  12. {
  13. ...
  14. if (!$success) {
  15. throw new RuntimeException(...);
  16. }
  17.  
  18. ...
  19. }

This helps to keep the code flow simple and easy to follow.

Typehinting

Arguments that expect objects, arrays or callbacks (callable) can be typehinted.We only typehint public methods, though, as typehinting is not cost-free:

  1. /**
  2. * Some method description.
  3. *
  4. * @param \Cake\ORM\Table $table The table class to use.
  5. * @param array $array Some array value.
  6. * @param callable $callback Some callback.
  7. * @param bool $boolean Some boolean value.
  8. */
  9. public function foo(Table $table, array $array, callable $callback, $boolean)
  10. {
  11. }

Here $table must be an instance of \Cake\ORM\Table, $array must bean array and $callback must be of type callable (a valid callback).

Note that if you want to allow $array to be also an instance of\ArrayObject you should not typehint as array accepts only the primitivetype:

  1. /**
  2. * Some method description.
  3. *
  4. * @param array|\ArrayObject $array Some array value.
  5. */
  6. public function foo($array)
  7. {
  8. }

Anonymous Functions (Closures)

Defining anonymous functions follows the PSR-2 coding style guide, where they aredeclared with a space after the function keyword, and a space before and afterthe use keyword:

  1. $closure = function ($arg1, $arg2) use ($var1, $var2) {
  2. // code
  3. };

Method Chaining

Method chaining should have multiple methods spread across separate lines, andindented with four spaces:

  1. $email->from('foo@example.com')
  2. ->to('bar@example.com')
  3. ->subject('A great message')
  4. ->send();

Commenting Code

All comments should be written in English, and should in a clear way describethe commented block of code.

Comments can include the following phpDocumentortags:

PhpDoc tags are very much like JavaDoc tags in Java. Tags are only processed ifthey are the first thing in a DocBlock line, for example:

  1. /**
  2. * Tag example.
  3. *
  4. * @author this tag is parsed, but this @version is ignored
  5. * @version 1.0 this tag is also parsed
  6. */
  1. /**
  2. * Example of inline phpDoc tags.
  3. *
  4. * This function works hard with foo() to rule the world.
  5. *
  6. * @return void
  7. */
  8. function bar()
  9. {
  10. }
  11.  
  12. /**
  13. * Foo function.
  14. *
  15. * @return void
  16. */
  17. function foo()
  18. {
  19. }

Comment blocks, with the exception of the first block in a file, should alwaysbe preceded by a newline.

Variable Types

Variable types for use in DocBlocks:

  • Type
  • Description
  • mixed
  • A variable with undefined (or multiple) type.
  • int
  • Integer type variable (whole number).
  • float
  • Float type (point number).
  • bool
  • Logical type (true or false).
  • string
  • String type (any value in ” ” or ‘ ‘).
  • null
  • Null type. Usually used in conjunction with another type.
  • array
  • Array type.
  • object
  • Object type. A specific class name should be used if possible.
  • resource
  • Resource type (returned by for example mysql_connect()).Remember that when you specify the type as mixed, you should indicatewhether it is unknown, or what the possible types are.
  • callable
  • Callable function.

You can also combine types using the pipe char:

  1. int|bool

For more than two types it is usually best to just use mixed.

When returning the object itself, e.g. for chaining, one should use $thisinstead:

  1. /**
  2. * Foo function.
  3. *
  4. * @return $this
  5. */
  6. public function foo()
  7. {
  8. return $this;
  9. }

Including Files

include, require, include_once and require_once do not haveparentheses:

  1. // wrong = parentheses
  2. require_once('ClassFileName.php');
  3. require_once ($class);
  4.  
  5. // good = no parentheses
  6. require_once 'ClassFileName.php';
  7. require_once $class;

When including files with classes or libraries, use only and always therequire_once function.

PHP Tags

Always use long tags (<?php ?>) instead of short tags (<? ?>). The shortecho should be used in template files where appropriate.

Short Echo

The short echo should be used in template files in place of <?php echo. Itshould be immediately followed by a single space, the variable or function valueto echo, a single space, and the php closing tag:

  1. // wrong = semicolon, no spaces
  2. <td><?=$name;?></td>
  3.  
  4. // good = spaces, no semicolon
  5. <td><?= $name ?></td>

As of PHP 5.4 the short echo tag (<?=) is no longer to be consider a ‘shorttag’ is always available regardless of the short_open_tag ini directive.

Naming Convention

Functions

Write all functions in camelBack:

  1. function longFunctionName()
  2. {
  3. }

Classes

Class names should be written in CamelCase, for example:

  1. class ExampleClass
  2. {
  3. }

Variables

Variable names should be as descriptive as possible, but also as short aspossible. All variables should start with a lowercase letter, and should bewritten in camelBack in case of multiple words. Variables referencing objectsshould in some way associate to the class the variable is an object of.Example:

  1. $user = 'John';
  2. $users = ['John', 'Hans', 'Arne'];
  3.  
  4. $dispatcher = new Dispatcher();

Member Visibility

Use PHP’s public, protected and private keywords for methods and variables.

Example Addresses

For all example URL and mail addresses use “example.com”, “example.org” and“example.net”, for example:

The “example.com” domain name has been reserved for this (see RFC 2606) andis recommended for use in documentation or as examples.

Files

File names which do not contain classes should be lowercased and underscored,for example:

  1. long_file_name.php

Casting

For casting we use:

  • Type
  • Description
  • (bool)
  • Cast to boolean.
  • (int)
  • Cast to integer.
  • (float)
  • Cast to float.
  • (string)
  • Cast to string.
  • (array)
  • Cast to array.
  • (object)
  • Cast to object.

Please use (int)$var instead of intval($var) and (float)$var insteadof floatval($var) when applicable.

Constants

Constants should be defined in capital letters:

  1. define('CONSTANT', 1);

If a constant name consists of multiple words, they should be separated by anunderscore character, for example:

  1. define('LONG_NAMED_CONSTANT', 2);

Careful when using empty()/isset()

While empty() is an easy to use function, it can mask errors and causeunintended effects when '0' and 0 are given. When variables orproperties are already defined, the usage of empty() is not recommended.When working with variables, it is better to rely on type-coercion to booleaninstead of empty():

  1. function manipulate($var)
  2. {
  3. // Not recommended, $var is already defined in the scope
  4. if (empty($var)) {
  5. // ...
  6. }
  7.  
  8. // Use boolean type coercion
  9. if (!$var) {
  10. // ...
  11. }
  12. if ($var) {
  13. // ...
  14. }
  15. }

When dealing with defined properties you should favour null checks overempty()/isset() checks:

  1. class Thing
  2. {
  3. private $property; // Defined
  4.  
  5. public function readProperty()
  6. {
  7. // Not recommended as the property is defined in the class
  8. if (!isset($this->property)) {
  9. // ...
  10. }
  11. // Recommended
  12. if ($this->property === null) {
  13.  
  14. }
  15. }
  16. }

When working with arrays, it is better to merge in defaults over usingempty() checks. By merging in defaults, you can ensure that required keysare defined:

  1. function doWork(array $array)
  2. {
  3. // Merge defaults to remove need for empty checks.
  4. $array += [
  5. 'key' => null,
  6. ];
  7.  
  8. // Not recommended, the key is already set
  9. if (isset($array['key'])) {
  10. // ...
  11. }
  12.  
  13. // Recommended
  14. if ($array['key'] !== null) {
  15. // ...
  16. }
  17. }