PHP code example of sanmai / phpstan-rules

1. Go to this page and download the library: Download sanmai/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/ */

    

sanmai / phpstan-rules example snippets


foreach ($users as $user) {
    foreach ($user->getPosts() as $post) { // Error: Nested loops are not allowed
        if ($post->isPublished()) {
            $titles[] = $post->getTitle();
        }
    }
}

use function Pipeline\take;

$titles = take($users)
    ->map(fn($user) => yield from $user->getPosts())
    ->filter(fn($post) => $post->isPublished())
    ->cast(fn($post) => $post->getTitle())
    ->toList();

if ($user->isActive()) {
    if ($user->hasPermission('edit')) { // Error: Nested if statements should be avoided
        $this->grantAccess();
    }
}

if ($user->isActive() && $user->hasPermission('edit')) {
    $this->grantAccess();
}

if (!$user->isActive()) {
    return;
}

if (!$user->hasPermission('edit')) {
    return;
}

$this->grantAccess();

foreach ($items as $item) {
    if ($item->isValid()) { // Error: Use guard clauses
        $item->process();
        $item->save();
    }
}

foreach ($items as $item) {
    if (!$item->isValid()) {
        continue;
    }
    
    $item->process();
    $item->save();
}

foreach ($items as $item) {
    if (count($buffer) >= $limit) { // OK: Loop has more than just the if
        array_shift($buffer);
    }
    
    $buffer[] = $item;
}

if ($user->isActive()) {
    return $user->getName();
} else { // Error: Else statements are not allowed
    return 'Guest';
}

if (!$user->isActive()) {
    return 'Guest';
}

return $user->getName();

if (empty($data)) { // Error: The empty() function is not allowed
    return null;
}

if (empty($items)) { // Error: Use $items === [] instead
    return 'No items';
}

// Be explicit about what you're checking
if ($data === null) {
    return null;
}

// For arrays
if ($items === []) {
    return 'No items';
}

// Exception: nullable arrays are allowed
function process(?array $items): void
{
    if (empty($items)) { // OK: cleaner than ($items === null || $items === [])
        return;
    }
    // process items...
}

function validateTag(string $tag): void
{
    if (empty($tag)) { // Error: empty() on strings - empty('0') returns true!
        throw new \InvalidArgumentException('Tag cannot be empty');
    }
}

// This will throw an exception even though '0' is a valid tag!
validateTag('0');

function validateTag(string $tag): void
{
    if ($tag === '') { // Explicit check that doesn't treat '0' as empty
        throw new \InvalidArgumentException('Tag cannot be empty');
    }
}

// For nullable strings, be explicit about both conditions
function process(?string $input): void
{
    if ($input === null || $input === '') {
        return;
    }
    // process input...
}

function processData(): void
{
    $this->initialize();

    if ($this->isValid()) { // Error: Use guard clause instead
        $this->transform();
        $this->validate();
        $this->save();
        $this->notify();
    }
}

function processData(): void
{
    $this->initialize();

    if (!$this->isValid()) {
        return;
    }

    $this->transform();
    $this->validate();
    $this->save();
    $this->notify();
}

if (count($items) === 0) { // Error: Avoid comparing count() with 0
    return 'No items';
}

if (count($items) > 0) { // Error: Avoid comparing count() with 0
    process($items);
}

if ($items === []) {
    return 'No items';
}

if ($items !== []) {
    process($items);
}

// Other count comparisons are fine
if (count($items) === 1) {
    return 'Single item';
}

final class UserService
{
    public function getUser(int $id): User
    {
        // ...
    }
}

class UserService
{
    public function getUser(int $id): User
    {
        // ...
    }
}

// Or with @final annotation
/**
 * @final
 */
class UserService
{
    public function getUser(int $id): User
    {
        // ...
    }

    // Private methods are not prohibited
    private function updateUsers(): void
    {

    }

    // Just as final methods are still discretionary
    final public function getAll(): iterable
    {

    }
}

/**
 * @phpstan-ignore sanmai.noFinalClasses
 */
final class SpecialCaseThatMustBeFinal
{
    // This final class will be ignored
}

class UserService
{
    public static function create(): self // First static method is fine
    {
        return new self();
    }

    public static function validate(User $user): bool // Error: Too many static methods
    {
        return $user->isValid();
    }
}

class UserService
{
    // Protected and private static methods are allowed
    private static function getConfig(): array
    {
        return [];
    }

    protected static function validate(): void
    {

    }
}

// Classes with private constructors are exempt (factory pattern)
class ValueObject
{
    private function __construct(private string $value) {}

    public static function fromString(string $value): self // Allowed
    {
        return new self($value);
    }

    public static function fromArray(array $data): self // Also allowed
    {
        return new self($data['value']);
    }
}