1. Go to this page and download the library: Download shipmonk/phpstan-rules library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
shipmonk / phpstan-rules example snippets
function example1(Money $fee1, Money $fee2) {
if ($fee1 > $fee2) {} // comparing objects is denied
}
new DateTime() > '2040-01-02'; // comparing different types is denied
200 > '1e2'; // comparing different types is denied
enum MyEnum: string { // missing @implements tag
case MyCase = 'case1';
}
/**
* @param list<Entity> $entities
* @return list<Uuid>
*/
public function getIds(array $entities): array {
return array_map(
function ($entity) { // missing native typehint; not reported with allowMissingTypeWhenInferred: true
return $entity->id;
},
$entities
);
}
enum MyEnum {
case Foo;
case Bar;
}
if ($enum === MyEnum::Foo) {
// ...
} elseif ($enum === MyEnum::Bar) { // always true reported by phpstan (for versions 1.10.0 - 1.10.34)
// ...
} else {
throw new LogicException('Unknown case'); // phpstan knows it cannot happen
}
$fn = function () {
yield new stdClass => 1;
};
iterator_to_array($fn()); // denied, would fail
/**
* @return array<string>
*/
public function returnList(): array // error, return phpdoc is generic array, but list is always returned
{
return ['item'];
}
class NoNativeReturnTypehint {
/**
* @return list<string>
*/
public function returnList() // error, missing array typehint
{
return ['item'];
}
}
class EnforceReadonlyPublicPropertyRule {
public int $foo; // fails, no readonly modifier
public readonly int $bar;
}
function add(string $a, string $b) {
return $a + $b; // denied, non-numeric types are allowed
}
class TransactionManager {
/**
* @param-immediately-invoked-callable $callback
*/
public function transactional(callable $callback): void {
// ...
$callback();
// ...
}
}
class UserEditFacade
{
/**
* @throws UserNotFoundException
*/
public function updateUserEmail(UserId $userId, Email $email): void
{
$this->transactionManager->transactional(function () use ($userId, $email) {
$user = $this->userRepository->get($userId); // can throw checked UserNotFoundException
$user->updateEmail($email);
})
}
public function getUpdateEmailCallback(UserId $userId, Email $email): callable
{
return function () use ($userId, $email) {
$user = $this->userRepository->get($userId); // this usage is denied, it throws checked exception, but you don't know when, thus it cannot be tracked by phpstan
$user->updateEmail($email);
};
}
}
class Provider {
/** @throws CheckedException */
public static function generate(): iterable
{
yield 1;
throw new CheckedException(); // denied, gets thrown once iterated
}
}
new SomeClass(); // Class SomeClass is forbidden. Please use different class
(new AnotherClass())->someMethod(); // Method AnotherClass::someMethod() is forbidden. Please use anotherMethod
enum MyEnum: string {
case MyCase = 'case1';
}
implode('', [MyEnum::MyCase]); // denied, would fail on implicit toString conversion
function example($unknown) {
$unknown->property; // cannot fetch property on mixed
}
$value = '2e0';
$value++; // would be float(3), denied
match ($enum) {
MyEnum::Case: 1;
default: 2; // default arm forbidden
}
function example($unknown) {
$unknown->call(); // cannot call method on mixed
}
/**
* @return mixed|false // denied, this is still just mixed
*/
public function getAttribute(string $name)
{
return $this->attributes[$name] ?? false;
}
function getCost(int $cost, ?int $surcharge): int {
$cost += $surcharge; // denied, adding possibly-null value
return $cost;
}
class Get {
public static function oneTwoThree(): iterable { // marked as iterable, caller cannot access the return value by Generator::getReturn
yield 1;
yield 2;
return 3;
}
}
iterator_to_array(Get::oneTwoThree()); // [1, 2] - see https://3v4l.org/Leu9j
$taxRates = [ // denied, float key gets casted to int (causing $taxRates to contain one item)
1.15 => 'reduced',
1.21 => 'standard',
];
function example(OrderId $id) {
$id = $id->getStringValue(); // denied, type changed from object to string
}
function example(MyClass $class) {
unset($class->field); // denied
}
public function example(int $foo): ?int { // null never returned
if ($foo < 0) {
return 0;
}
return $foo;
}
function validate(): void {
new Exception(); // forgotten throw
}
match ($foo) { // unused match result
case 'foo' => 1;
}
try {
// some code
} catch (RuntimeException $e) {
throw new LogicException('Cannot happen'); // $e not passed as previous
}
class MyException extends RuntimeException {
public function __construct() {
parent::__construct('My error');
}
}
try {
// some code
} catch (RuntimeException $e) {
throw new MyException(); // reported even though MyException cannot accept it yet
}
class Example
{
private ?int $field = null; // useless default value
public function __construct()
{
$this->field = 1;
}
}
class Example
{
private ?int $field; // useless nullability
public function __construct()
{
$this->field = 1;
}
public function setField(int $value)
{
$this->field = $value;
}
}
neon
parameters:
shipmonkRules:
forbidCast:
enabled: true
blacklist!: ['(unset)'] # force the blacklist to be only (unset)
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.