Use PSR-12 code style as base, read about it here https://www.php-fig.org/psr/psr-12/
You MUST format only code you add or change to reduce cognitive load for people doing PR reviews.
You SHOULD prefer selection formatting over full file formatting.
Import preconfigured setting from here: [<..todo settings link...>](http://<..todo settings link...>) or setup manually as described below.
In PhpStorm: Editor > Code Style > PHP > Set from...
choose PSR-12
.
Also you SHOULD enable PSR-12 inspections (disabled by default).
Most formating now can be done by IDE. You press Ctrl + Alt + L
to reformat current file or current selection.
Go to: Editor > Code Style > PHP > Wrapping and Braces
-
Function/constructor call arguments - Chop down if long
- Align when multiline - disabled
- New line after '(' - disabled
- Place ')' on new line - disabled
- Place '()' for constructor - always
-
Array initializer - Chop down if long
- Align key-value pairs - enabled
- New line after ')' - enabled
- Place ')' on new line - enabled
Good:
$x = [
"x",
"y",
[
1 => "abc",
2 => "def",
3 => "ghi",
],
];
$devices->each(
function (Device $device) use ($sample, $org) {
factory(Sample::class)->create([
'device_id' => $device->id,
'percent_remaining' => $sample,
'organization_id' => $org->id,
]);
}
);
Bad:
$x = ["x",
"y",
[1 => "abc",
2 => "def",
3 => "ghi"]];
$devices->each(
function (Device $device) use ($sample, $org) {
factory(Sample::class)->create([
'device_id' => $device->id,
'percent_remaining' => $sample,
'organization_id' => $org->id,
]);
}
);
All the rules are not retroactive and MUST be used only for new and refactored code.
Example:
<?php declare(strict_types=1);
Good:
function hello(): void
{
}
Bad:
function hello()
{
}
Good:
function hello(string $name): void
{
}
Bad:
function hello($name): void
{
}
Where possible try to have predicate methods for checking existense.
Good:
function hasName(): bool
{
}
function getName(): string
{
}
Acceptable:
function getName(): ?string
{
}
Add only if function/interface throws or you really need to describe it. Most of the parameters are infered by modern IDEs from signature.
Good:
/**
* Very helpful description
*
* @param Device $device
*
* @return RefillTaskHandlerInterface
* @throws ShoulNotBeHandledException
*/
public function getHandler(Device $device): RefillTaskHandlerInterface
{}
Bad (everything from this block can be infered from signature):
/**
* @param Device $device
*
* @return bool
*/
public function hasHandler(Device $device): bool
{}
#M6 - SHOULD write PHPStan compatible comments. https://phpstan.org/writing-php-code/phpdoc-types
Good:
/**
* @param Collection<RefillTask> $refillTasks
*/
protected function notifyBatch(Collection $refillTasks): void
Acceptable:
/**
* @param Collection|RefillTask[] $refillTasks
*/
protected function notifyBatch(Collection $refillTasks): void
Main codebase rules plus...
Good:
/** @test */
public function is_low_when_no_samples_returns_false(): void
Bad:
public function test_is_low_when_no_samples_returns_false(): void
Good:
public function method_returns_zero(): void
Bad:
public function methodReturnsZero(): void
Good:
public function bar_method_returns_zero(): void
{
$class = new \Foo():
$this->assertSame(0, $class->bar());
}
Bad:
public function everything_is_valid(): void
{
$class = new \Foo();
$class->calculate(3, 5);
$this->assertSame(0, $class->bar());
$this->assertEquals('status', $class->getStatus());
}
When testing method call result: <method_name>_<condition>_?<tested object>_<expected result>
When testing some action/behavior: <condition>_?<tested object>_<expected result>
Good:
public function show_page_when_have_multi_device_dispenser_has_all_devices_present_on_page(): void
public function when_dispenser_is_low_page_has_alert_tag(): void
Acceptable:
public function show_page_can_be_seen_by_admin(): void
public function has_organization_relation(): void // i.e. when testing a Model
Bad:
public function files(): void
public function was_created(): void
public function can_see_it(): void
Consider other developers adding tests to files you created, they would have to deal with overhead of created models they do not want to use (.i.e. to make a count() assert against same model).
Also this makes all dependencies explicitly visible in each test and easier to understand.
Main guidline when writing arrange/act/assert stages - to ask yourself: "Can I understand whats going on if I come back here in 6 months?"
Good:
public function my_test(): void
{
$user = factory(User::class)->create();
$restroom = factory(Restroom::class)->create();
$secret = str_random(40);
config()->set('app.api_secret', $secret);
// your test case...
}
Bad:
public function setUp(): void
{
parent::setUp();
$this->user = factory(User::class)->create();
$this->restroom = factory(Restroom::class)->create();
$this->secret = str_random(40);
config()->set('app.api_secret', $this->secret);
}
public function my_test(): void
{
// your test case...
}