Skip to content

NormanAlbert91/functional-php

Repository files navigation

PHPStan Functional PHP

A PHPStan plugin to enforce pure functional programming in PHP.

Installation

Add the repository to your composer.json:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "git@github.com:NormanAlbert91/functional-php.git"
        }
    ]
}

Then install the package:

composer require --dev na/functional-php:dev-main

If you use phpstan/extension-installer, the plugin is automatically registered. Otherwise, add to your phpstan.neon:

includes:
    - vendor/na/functional-php/extension.neon

Rules

ImmutableVariableRule

Variables cannot be reassigned.

$x = 1;
$x = 2;      // Error: Variable $x is being reassigned
$x += 1;     // Error: Variable $x is being reassigned

NoLoopRule

No for, while, or do-while loops. Use array_map, array_filter, array_reduce instead.

for ($i = 0; $i < 10; $i++) {}   // Error
while ($condition) {}            // Error
do {} while ($condition);        // Error

foreach ($items as $item) {}     // OK - foreach is allowed
array_map(fn($x) => $x * 2, $items);  // OK

NoMutatingArrayFunctionsRule

No functions that mutate arrays in-place.

sort($array);                    // Error: Use [...$array] with usort()
array_push($array, $value);      // Error: Use [...$array, $value]
array_pop($array);               // Error: Use array_slice()
shuffle($array);                 // Error

$sorted = [...$array];
usort($sorted, fn($a, $b) => $a <=> $b);  // OK - copy first
$new = [...$array, $value];               // OK - spread operator

NoGlobalStateRule

No global variables, superglobals, or static function variables.

global $config;                  // Error
$_GET['id'];                     // Error
$_SESSION['user'];               // Error

function counter() {
    static $count = 0;           // Error: Hidden state
}

NoVoidReturnRule

All functions must return a value. No void or never return types.

function doSomething(): void {}  // Error: Pure functions must return a value
function log($msg) {}            // Error: Must have a return type

function add(int $a, int $b): int {
    return $a + $b;              // OK
}

NoEchoRule

No direct output. Return values instead.

echo 'Hello';                    // Error
print 'World';                   // Error
var_dump($data);                 // Error
exit(1);                         // Error
die('error');                    // Error

return 'Hello World';            // OK

NoReferenceParameterRule

No pass-by-reference parameters. Return new values instead.

function increment(int &$value) {}  // Error: Reference parameters allow mutation

function increment(int $value): int {
    return $value + 1;              // OK
}

NoStaticPropertyRule

No static properties. They are global mutable state.

class Singleton {
    private static ?self $instance = null;  // Error
}

Counter::$count;                 // Error: Accessing static properties

NoNonDeterministicFunctionsRule

No functions with non-deterministic output. Inject dependencies instead.

// Random - inject a random generator
rand(1, 100);                    // Error
random_int(1, 100);              // Error

// Time - inject a Clock interface
time();                          // Error
new DateTime();                  // Error
new DateTimeImmutable();         // Error

// Filesystem - inject a filesystem interface
file_get_contents('file.txt');   // Error
file_exists('file.txt');         // Error

// Network - inject an HTTP client
curl_exec($ch);                  // Error

// Process - inject a process runner
exec('ls');                      // Error
shell_exec('ls');                // Error

RequireReadonlyClassRule

All class properties must be readonly.

class User {
    public string $name;         // Error: Must be readonly
}

class User {
    public readonly string $name;  // OK
}

readonly class User {
    public string $name;           // OK - readonly class
}

Philosophy

This plugin enforces the core principles of functional programming:

  1. Immutability - Data never changes after creation
  2. Pure Functions - Same input always produces same output, no side effects
  3. Determinism - No hidden dependencies on external state
  4. Explicit Dependencies - All dependencies passed as parameters

About

Force php to be functional

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages