docs/internals/core-code-style.md
The following code style is used for Yii 2.x core and official extensions development. If you want to pull-request code into the core, consider using it. We aren't forcing you to use this code style for your application. Feel free to choose what suits you better.
You can get a config for CodeSniffer here: https://github.com/yiisoft/yii2-coding-standards
Overall we're using PSR-2 compatible style so everything that applies to PSR-2 is applied to our code style as well.
<?php or <?= tags.StudlyCaps.camelCase.camelCase.elseif instead of else if.<?php ?> or <?= tags; it MUST NOT use the other tag variations such as <?.?>..php.PHP code MUST use only UTF-8 without BOM.
Class names MUST be declared in StudlyCaps. For example, Controller, Model.
The term "class" refers to all classes and interfaces here.
StudlyCase./**
* Documentation
*/
class MyClass extends \yii\base\BaseObject implements MyInterface
{
// code
}
Class constants MUST be declared in all upper case with underscore separators. For example:
<?php
class Foo
{
const VERSION = '1.0';
const DATE_APPROVED = '2012-06-01';
}
public keyword explicitly.$_varName.$camelCase
with first letter lowercase.$i and $j are better not to be used.For example:
<?php
class Foo
{
public $publicProp1;
public $publicProp2;
protected $protectedProp;
private $_privateProp;
public function someMethod()
{
// ...
}
}
camelCase with first letter lowercase.private, protected and
public modifiers. var is not allowed./**
* Documentation
*/
class Foo
{
/**
* Documentation
*/
public function bar()
{
// code
return $value;
}
}
@param, @var, @property and @return must declare types as bool, int, string, array or null.
You can use a class names as well such as Model or ActiveRecord.ClassName[].isActive, hasClass, etc) the first line should start with Checks whether.@return should explicitly describe what exactly will be returned./**
* Checks whether the IP is in subnet range
*
* @param string $ip an IPv4 or IPv6 address
* @param int $cidr the CIDR length
* @param string $range subnet in CIDR format e.g. `10.0.0.0/8` or `2001:af::/64`
* @return bool whether the IP is in subnet range
*/
private function inRange($ip, $cidr, $range)
{
// ...
}
__construct should be used instead of PHP 4 style constructors.true, false, null and array.Changing type of an existing variable is considered as a bad practice. Try not to write such code unless it is really necessary.
public function save(Transaction $transaction, $argument2 = 100)
{
$transaction = new Connection; // bad
$argument2 = 200; // good
}
$str = 'Like this.';
$str1 = "Hello $username!";
$str2 = "Hello {$username}!";
The following is not permitted:
$str3 = "Hello ${username}!";
Add spaces around dot when concatenating strings:
$name = 'Yii' . ' Framework';
When string is long format is the following:
$sql = "SELECT *"
. "FROM `post` "
. "WHERE `id` = 121 ";
For arrays we're using PHP 5.4 short array syntax.
Use the following formatting when declaring array:
$arr = [3, 14, 15, 'Yii', 'Framework'];
If there are too many elements for a single line:
$arr = [
3, 14, 15,
92, 6, $test,
'Yii', 'Framework',
];
Use the following format for associative arrays:
$config = [
'name' => 'Yii',
'options' => ['usePHP' => true],
];
if ($event === null) {
return new Event();
}
if ($event instanceof CoolEvent) {
return $event->instance();
}
return null;
// the following is NOT allowed:
if (!$model && null === $event)
throw new Exception('test');
Prefer avoiding else after return where it makes sense.
Use guard conditions.
$result = $this->getResult();
if (empty($result)) {
return true;
} else {
// process result
}
is better as
$result = $this->getResult();
if (empty($result)) {
return true;
}
// process result
Use the following formatting for switch:
switch ($this->phpType) {
case 'string':
$a = (string) $value;
break;
case 'integer':
case 'int':
$a = (int) $value;
break;
case 'boolean':
$a = (bool) $value;
break;
default:
$a = null;
}
doIt(2, 3);
doIt(['a' => 'b']);
doIt('a', [
'a' => 'b',
'c' => 'd',
]);
Note space between function/use tokens and open parenthesis:
// good
$n = 100;
$sum = array_reduce($numbers, function ($r, $x) use ($n) {
$this->doMagic();
$r += $x * $n;
return $r;
});
// bad
$n = 100;
$mul = array_reduce($numbers, function($r, $x) use($n) {
$this->doMagic();
$r *= $x * $n;
return $r;
});
Refer to phpDoc for documentation syntax.
Code without documentation is not allowed.
All class files must contain a "file-level" docblock at the top of each file and a "class-level" docblock immediately above each class.
There is no need to use @return if method does return nothing.
All virtual properties in classes that extend from yii\base\BaseObject
are documented with an @property tag in the class doc block.
These annotations are automatically generated from the @return or @param
tag in the corresponding getter or setter by running ./build php-doc in the build directory.
You may add an @property tag
to the getter or setter to explicitly give a documentation message for the property
introduced by these methods when description differs from what is stated
in @return. Here is an example:
<?php
/**
* Returns the errors for all attribute or a single attribute.
* @param string $attribute attribute name. Use null to retrieve errors for all attributes.
* @property array An array of errors for all attributes. Empty array is returned if no error.
* The result is a two-dimensional array. See [[getErrors()]] for detailed description.
* @return array errors for all attributes or the specified attribute. Empty array is returned if no error.
* Note that when returning errors for all attributes, the result is a two-dimensional array, like the following:
* ...
*/
public function getErrors($attribute = null)
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/
/**
* Component is the base class that provides the *property*, *event* and *behavior* features.
*
* @include @yii/docs/base-Component.md
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Component extends \yii\base\BaseObject
/**
* Returns the list of attached event handlers for an event.
* You may manipulate the returned [[Vector]] object by adding or removing handlers.
* For example,
*
* ```
* $component->getEventHandlers($eventName)->insertAt(0, $eventHandler);
* ```
*
* @param string $name the event name
* @return Vector list of attached event handlers for the event
* @throws Exception if the event is not defined
*/
public function getEventHandlers($name)
{
if (!isset($this->_e[$name])) {
$this->_e[$name] = new Vector;
}
$this->ensureBehaviors();
return $this->_e[$name];
}
As you can see in the examples above we use markdown to format the phpDoc comments.
There is additional syntax for cross linking between classes, methods and properties in the documentation:
[[canSetProperty]] will create a link to the canSetProperty method or property of the same class.[[Component::canSetProperty]] will create a link to canSetProperty method of the class Component in the same namespace.[[yii\base\Component::canSetProperty]] will create a link to canSetProperty method of the class Component in namespace yii\base.[[Component]] will create a link to the Component class in the same namespace. Adding namespace to the class name is also possible here.To give one of the above mentioned links another label than the class or method name you can use the syntax shown in the following example:
... as displayed in the [[header|header cell]].
The part before the | is the method, property or class reference while the part after | is the link label.
It is also possible to link to the Guide using the following syntax:
[link to guide](guide:file-name.md)
[link to guide](guide:file-name.md#subsection)
Code examples should use Markdown syntax, but they should not specify the language. Specifying a language in code examples may break their display in some IDEs. Here is an example:
/**
* Correct code example:
*
* ```
* $object->doMagic();
* ```
*/
function doMagic()
{
}
/**
* Incorrect code example:
*
* ```php
* $object->doMagic();
* ```
*/
function doMagic()
{
}
// and not #.=== [] vs empty()Use empty() where possible.
Return early when conditions nesting starts to get cluttered. If the method is short it doesn't matter.
self vs. staticAlways use static except the following cases:
self: self::MY_CONSTANTself: self::$_eventsself for method calls where it makes sense such as recursive call to current implementation instead of extending classes implementation.Properties allowing to configure component not to do something should accept value of false. null, '', or [] should not be assumed as such.