Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<?php
/**
* When defining parameters, in what case should we:
* - add the question mark (?) before the type?
* - add the default value
*
* In this example `MyClass` can be replaced by any class or any scalar type (int, string, array, iterable, object...)
*/
class Foo
{
/**
* If possive, always do the stricter way if possible: no null possible, a type is forced
*/
public function foo(MyClass $param)
{
// This is the only way to call this method, it ensures we pass the expected type which is not null
$this->foo(new MyClass());
}
/**
* If the param is optionnal, a default value must be added.
* It means we can omit the parameter, and it will have the default value.
*/
public function foo(MyClass $param = null)
{
// The method can be called in two ways
$this->foo();
$this->foo(new MyClass());
// $this->foo(null); // Will throw a fatal
}
/**
* If the param is NOT OPTIONNAL but can be null, the question mark must be added.
* It means we are forced to call with a parameter, even it is null.
*
* This is particularly suited for setters method.
*/
public function foo(?MyClass $param)
{
// Can be called in these ways
$this->foo(null);
$this->foo(new MyClass());
// $this->foo(); // Will throw a fatal
}
/**
* If the param is optionnal AND can be null, the question mark must be added and default value must be added.
* This is most evasive way of defining parameters and it really should be used in last choice since
* it created multiple cases to handle (nullable + default values)
*/
public function foo(?MyClass $param = null)
{
// Can be called in these ways
$this->foo(null);
$this->foo();
$this->foo(new MyClass());
}
/**
* More complex examples with multiple parameters
*/
public function foo(MyClass $param1, MyClass $param = null)
{
// Can be called in these ways
$this->foo(new MyClass());
$this->foo(new MyClass(), new MyClass());
}
public function foo(MyClass $param1, ?MyClass $param)
{
// Can be called in these ways
$this->foo(new MyClass(), null);
$this->foo(new MyClass(), new MyClass());
// This case is weird and should never be used
}
public function foo(MyClass $param1, ?MyClass $param = null)
{
// Can be called in these ways
$this->foo(new MyClass());
$this->foo(new MyClass(), null);
$this->foo(new MyClass(), new MyClass());
}
}
<?php
/**
* When defining return type, in what case should we:
* - set a PHP return type?
* - set a PHPDoc return type?
* - add the question mark (?) before the type?
*
* In this example `MyClass` can be replaced by any class or any scalar type (int, string, array, iterable, object...)
*/
class Foo
{
/**
* If possive, always do the stricter way if possible: no null possible, a type is forced
*/
public function foo(): MyClass
{
}
/**
* If the return value can be null, add the question mark.
*/
public function foo(): ?MyClass
{
}
/**
* If the return value is not totally describing the exact return type, it must be specified in PHPDoc.
* With this example, IDE will understand that the return of foo() is an array of MyClass objects.
* It will detect it in foreach loops, etc.
*
* @return MyClass[]
*/
public function foo(): array
{
return [
new MyClass(),
new MyClass(),
];
}
/**
* In this example, IDE will have no idea of the type of the array items
*/
public function foo(): array
{
return [
new MyClass(),
new MyClass(),
];
}
/**
* Most of the time, this example must be avoided, because a "null" value instead of an array
* is likely the same thing as an "empty array". This rule also applies for array passed as parameters.
*/
public function foo(): ?array
{
}
/* ================================
* Bonus: complex array structures.
* ================================ */
/**
* PHPStan can understand psalm annotations which allow describing complex array structures.
* PHPStorm will understand this notation in the end of 2020.
*
* @psalm-return array<string, MyClass>
*/
public function foo(): array
{
return [
'foo' => new MyClass(),
'bar' => new MyClass(),
];
}
/**
* @psalm-return array<string, array<MyClass>>
*/
public function foo(): array
{
return [
'foo' => [new MyClass(), new MyClass()],
'bar' => [new MyClass()],
];
}
}
@itaelle
Copy link

itaelle commented Sep 22, 2020

Shall we not move this to our internal documentation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment