Code style guide
Edit on GitHubWe at Spryker follow the PSR-2 standards as the coding style guide. To achieve a styled codebase, we integrated the well known PHP-CS Fixer and PHPCodeSniffer.
Code Sniffer and Fixer
Code Sniffer helps to keep the code clean and to prevent simple mistakes. To make the most of the Code Sniffer, follow the recommendations below.
Automate code style correction
The sniffer can find all the issues and auto-fix most of them (when used with -f
option):
$ vendor/bin/console code:sniff:style
// Fix fixable errors instead of just reporting
$ vendor/bin/console code:sniff:style -f
// Sniff a specific module in your project (looks into all application layers Zed, Yves, Client, ...)
$ vendor/bin/console code:sniff:style -m Discount
// Sniff a specific subfolder of your project
$ vendor/bin/console code:sniff:style src/Pyz/Zed
// Run a specific sniff only
$ vendor/bin/console code:sniff:style ... -s Spryker.Commenting.FullyQualifiedClassNameInDocBlock
c:s:s
can be used as a shortcut.
Additional options:
-v:
Verbose output-d:
Dry-run, only output the command to be run
Always commit your changes before executing this command!
Run –help
or -h
to get help about the usage of all the available options.
See the code sniffer documentation for details and information on how to set it up for your CI system as a checking tool for each PR.
Make the necessary project adjustments
Make sure you change the composer package name of your application once you forked or copied the Demo Shop code. By default, the tool reads the name in the main composer.json
:
"name": "spryker-shop/suite",
Modify this in order to skip the MIT license checks.
The code sniffer documentation shows how to extend and customize the sniffer rules in general for your project.
Conventions and guidelines
We highly recommend following the best practices described below, as they help you to avoid certain classes of problems. These are more guidelines than absolute rules. If you feel the need to deviate from them, please document why you are doing so.
Use statements
Use statements must be ordered.
Alias for use
When you need an alias to use a Spryker class, follow this naming: use Spryker\Foo\Bar as SprykerBar;
Do not use CoreBar
or any other naming.
One Programming language per file
Always use one programming language per file. This allows us to use language-specific tooling on those files. This means no inline JavaScript or CSS, no generation of HTML in PHP, no execution of raw SQL statements from PHP. (Currently, all *Table.php files are an exception to this, HTML is allowed here.)
Comparison
Don’t use loose comparison, always be as strict as possible.
Bad:
getFoo()))
Good:
getFoo();
if ($b === static::SOME_CONST)
Only use empty()
and isset()
where the variable or array key could possibly not exist:
Bad:
getVar();
if (empty($var)) {
}
Good:
getVar();
if (!$var) {
}
You can also be more strict and use !== null
check, especially if the returned value is either an object or not (null).
Typecasting
Don’t use intval()
or other casting functions. Use (int)
, (bool)
, etc.
Don’t use !!
to cast to bool, use (bool)
. There is no space after casts.
String functions
Always use the multibyte string functions when available (Multibyte String Functions) and where non-ASCII input is possible.
The performance costs are negligible, but you can easily see where you might still use the wrong function.
Switch statements
Don’t use switch statements in PHP. They only make loose comparisons, and it’s easy to mess up the break.
Return early and else
Return as soon as you know your method cannot do some meaningful work anymore. Reduce indentation by using if/return
instead of the top-level if/else
. Try to keep the body of your method at the lowest indentation level. Using else
is almost always a code smell. Read up on how to refactor to return early
if you find yourself in deeply nested conditions.
Return types
All functions and methods need to declare a @return
statement.
Do not use return statements for constructor __construct()
and destructor __destruct()
, as per definition both of them cannot return anything.
Be explicit about your return type. Even though return;
and return null;
are technically the same, we make a semantic differentiation between them. This way, we can also see when a return parameter was forgotten or someone tries to use a void method.
returnEarly()) {
return;
}
// ...
}
/**
* @return Object|null
*/
public function doReturnSth()
{
if ($this->shouldReturnEarly()) {
return null;
}
$object = ...;
return $object;
}
Bottom line: use void
if nothing is expected to be returned, use null
otherwise, or if mixed with others. Try to return only one type, as mixed return types are often a code smell. Also, a proper object is better than associative arrays most of the time.
Avoid “no-op” methods
foo()
, which does not do any operation at all.
So semantically, this makes no sense. In this case, no default value may be used, and a first argument is actually required for the first if statement to make sense ($this->foo($requiredArgument)
). You can still pass null
, of course, to break out early. Default values may only be used if they still make this method do an operation (apart from returning early
).
Date and time
Always use UTC date and time when you are storing and processing them. The only place dates and times should be converted to a different time zone is in the Presentation layer. Storing the dates in a common time zone ensures consistency, as the time zone could be used in different contexts. For example, in a US shop, a customer from California (GMT-8) might place an order on the Storefront and a Back Office manager from New York (GMT -5) might need to know when the order was placed. Having the date time in a common time zone ensures that the timestamps are the same and accurate for the same operation, irrespective of the use case scenario.
Deprecations
When you deprecate a method, class, or alike, it is recommended to add a short sentence on what to use instead, so all people know what to do without having to investigate deeper.
DEPRECATION | MESSAGE |
---|---|
$userEntityCollection | Collection of transfer objects of the Propel user entity |
Scalar (string or int) | |
$idUser | User ID (int) |
$userIds | plural for user IDs (int[ ]) |
$users | Array with the user-related data |
$isValidatedPassword $hasPassword |
boolean |
$i, $j, $x, $y, $k, $m | Pointer in loops |
Naming of methods
TYPE | METHOD |
---|---|
singular | getFoo() / setFoo() |
plural | getFoos() / setFoos() |
boolean | getIsActive() / setIsActive(), optionally hasActive() to only check |
Find or not (nullable) | find…() |
Get or throw exception (not nullable), applies to empty collection returns) | get…() |
Check if exists - usually used with get | has….() |
Check if something non-specific exists | …Exists() |
Retrieves a transfer object of a propel object (PyzUserEntityTransfer ) |
getUserEntity() |
Retrieves a custom user transfer object | getUser() getUserTransfer() |
Get an indexed array of single values/objects (one key - one value) | getXXXIndexedByYYY() For example, getProductNamesIndexedByIdProduct(array $productAbstracts) |
Get an array of value/object collection grouped by some criteria (one key - multiple values) | getXXXGroupedByYYY() For example, getOrderItemsGroupedByIdShipment(array $orderItems) |
Thank you!
For submitting the form