<?php

declare(strict_types=1);

/**
 * ============================================================
 * VARIANTA 1
 * Jednoduchá request-level cache pomocí static proměnných
 * ============================================================
 */

function getExpensiveData(): mixed
{
    static $loaded = false;
    static $data;

    if (!$loaded) {
        $data = loadFromDatabase();
        $loaded = true;
    }

    return $data;
}



/**
 * ============================================================
 * VARIANTA 3
 * Univerzální memoize wrapper (funkcionální přístup)
 * ============================================================
 */

function memoize(callable $fn): callable
{
    $loaded = false;
    $cache = null;

    return function () use ($fn, &$loaded, &$cache) {
        if (!$loaded) {
            $cache = $fn();
            $loaded = true;
        }

        return $cache;
    };
}

// Použití:
// $getData = memoize(fn() => loadFromDatabase());
// $result = $getData();



/**
 * ============================================================
 * VARIANTA 4
 * OOP přístup se statickou cache a helper metodou remember()
 * ============================================================
 */

class DataProvider
{
    private static array $cache = [];

    private static function remember(string $key, callable $callback): mixed
    {
        if (!array_key_exists($key, self::$cache)) {
            self::$cache[$key] = $callback();
        }

        return self::$cache[$key];
    }

    public static function getUsers(): array|null
    {
        return self::remember('users', function () {
            return loadUsersFromDatabase();
        });
    }

    public static function getOrders(): array|null
    {
        return self::remember('orders', function () {
            return loadOrdersFromDatabase();
        });
    }
}



/**
 * ============================================================
 * Simulace drahých funkcí (jen pro testování)
 * ============================================================
 */

function loadFromDatabase(): ?array
{
    // simulace expensive operace
    sleep(1);

    return ['example' => 'data'];
}

function loadUsersFromDatabase(): ?array
{
    sleep(1);
    return ['user1', 'user2'];
}

function loadOrdersFromDatabase(): ?array
{
    sleep(1);
    return ['order1', 'order2'];
}