Является ли функция time() в PHP чистой (pure function)?

Ответ

Нет, функция time() в PHP не является чистой.

Чистая функция должна соответствовать двум критериям:

  1. Детерминированность: Для одинаковых входных аргументов всегда возвращает одинаковый результат.
  2. Отсутствие побочных эффектов (side-effects): Не изменяет внешнее состояние (глобальные переменные, файлы, БД).

Функция time() нарушает первый критерий, так как ее результат зависит от внешнего, изменяющегося состояния — системного времени.

// НЕ чистая функция: результат разный при каждом вызове.
echo time(); // 1710000000
sleep(1);
echo time(); // 1710000001

Как сделать код, зависящий от времени, тестируемым? Инкапсулируйте зависимость.

// 1. Внедрение зависимости через параметр (предпочтительно для чистоты).
function formatOrderDate(int $timestamp): string {
    return date('Y-m-d H:i:s', $timestamp);
}
// В тесте можем передать любое фиксированное время.
formatOrderDate(1672531200); // '2023-01-01 00:00:00'

// 2. Использование инъекции зависимости в классе.
class TimeSensitiveService {
    private $timeProvider;

    public function __construct(callable $timeProvider = null) {
        $this->timeProvider = $timeProvider ?? 'time';
    }

    public function isCacheValid(int $cacheTime): bool {
        $currentTime = ($this->timeProvider)();
        return ($currentTime - $cacheTime) < 3600;
    }
}
// В продакшене: new TimeSensitiveService();
// В тесте:    new TimeSensitiveService(fn() => 1672531200);

Ответ 18+ 🔞

А, ну это ж классика, блядь! Чистые функции — это как обещание не пить в пятницу: звучит красиво, но на деле постоянно кто-то срывается. И главный нарушитель спокойствия — этот ваш time().

Смотри, чистая функция — это святое, ёпта. Два железных правила: дала одинаковые аргументы — получишь одинаковый ответ, и при этом она нихуя вокруг себя не ломает и не пачкает. Никаких глобальных переменных, записей в базу или, ядрёна вошь, вывода в консоль.

А теперь посмотри на этого подлеца, time(). Он что делает? Каждый раз, когда его вызываешь, он смотрит на часы и выдаёт новую цифру. Это ж полный пиздец с точки зрения детерминированности! Сегодня он вернёт одно, через секунду — уже другое. Какое тут, на хуй, тестирование? Ты не можешь написать тест и быть уверенным, что завтра он сработает так же. Это же доверия ебать ноль.

// Это не функция, а обманщик с тремя картами.
echo time(); // Допустим, 1710000000
sleep(1); // Подождали чуть...
echo time(); // Бля, а уже 1710000001! Изменщик!

Так как же быть, если время нужно? А вот тут надо включать э бошка думай. Нельзя просто так взять и вызвать time() посреди своей бизнес-логики. Это путь в ад непроверяемого кода.

Самый правильный подход — это инкапсулировать эту зависимость, как опасную болезнь в карантин. Сделать так, чтобы твоя логика принимала время как аргумент, а не выпрашивала его у системы сама.

// 1. Способ для аристократов: передаём время параметром.
function formatOrderDate(int $timestamp): string {
    return date('Y-m-d H:i:s', $timestamp);
}
// В тесте мы — боги. Диктуем любое время.
formatOrderDate(1672531200); // Всегда будет '2023-01-01 00:00:00'. Красота!

// 2. Способ для ООП-шников: внедряем "поставщика времени" в класс.
class TimeSensitiveService {
    private $timeProvider; // Сюда мы засунем либо стандартный time(), либо свою заглушку

    public function __construct(callable $timeProvider = null) {
        // Если нам не подсунули свою функцию, используем стандартную, грешную.
        $this->timeProvider = $timeProvider ?? 'time';
    }

    public function isCacheValid(int $cacheTime): bool {
        $currentTime = ($this->timeProvider)(); // Вот тут магия!
        return ($currentTime - $cacheTime) < 3600;
    }
}
// В реальной работе: $service = new TimeSensitiveService(); // Использует time()
// В тестовой песочнице: $service = new TimeSensitiveService(fn() => 1672531200); // Время заморожено!

Вот видишь разницу? В первом случае функция чистая, как слеза младенца. Во втором — класс становится предсказуемым. Мы можем в тестах подсунуть ему заглушку, которая всегда возвращает одно и то же число, и наш код будет вести себя стабильно. А в бою он спокойно работает с реальным временем.

Итог простой: time()хитрая жопа, которая ломает чистоту. Но если эту зависимость вынести за скобки и контролировать её извне, то жить можно. И тесты писать можно. И спать спокойно.