Что такое «чистые» функции в программировании?

«Что такое «чистые» функции в программировании?» — вопрос из категории PHP Core, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Чистые функции (pure functions) — это функции, которые обладают двумя ключевыми свойствами:

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

Пример чистой функции в PHP:

// Чистая функция
function calculateDiscount(float $price, float $discountPercent): float {
    return $price * (1 - $discountPercent / 100);
}

// Использование
$finalPrice = calculateDiscount(1000, 15); // Всегда 850
$finalPrice2 = calculateDiscount(1000, 15); // Снова 850 - детерминировано

Пример НЕчистой функции:

// Нечистая функция - зависит от внешнего состояния
$taxRate = 20;

function calculatePriceWithTax(float $price): float {
    global $taxRate; // Зависимость от глобальной переменной
    $taxRate += 1; // Побочный эффект - изменение внешнего состояния
    return $price * (1 + $taxRate / 100);
}

// Результат зависит от порядка вызовов
$price1 = calculatePriceWithTax(1000); // 1210 (если taxRate был 20)
$price2 = calculatePriceWithTax(1000); // 1221 - разный результат!

Преимущества чистых функций:

1. Предсказуемость и надежность:

// Легко рассуждать о поведении
$result = calculateDiscount(1000, 10);
// Гарантированно вернет 900, независимо от контекста

2. Простота тестирования:

// Не нужны моки и сложная настройка окружения
public function testCalculateDiscount(): void
{
    $this->assertEquals(850, calculateDiscount(1000, 15));
    $this->assertEquals(0, calculateDiscount(0, 50));
    $this->assertEquals(1000, calculateDiscount(1000, 0));
}

3. Возможность кэширования (мемоизация):

// Реализация простого кэша для чистой функции
function memoizedCalculateDiscount(float $price, float $discountPercent): float {
    static $cache = [];
    $key = $price . '|' . $discountPercent;

    if (!isset($cache[$key])) {
        $cache[$key] = $price * (1 - $discountPercent / 100);
    }

    return $cache[$key];
}

4. Параллельное выполнение:

// Чистые функции можно безопасно выполнять параллельно
$prices = [100, 200, 300, 400];
$discountedPrices = array_map(
    fn($price) => calculateDiscount($price, 20),
    $prices
);
// Можно распараллелить без риска гонок данных

5. Референциальная прозрачность:

// Вызов функции можно заменить ее результатом
$total = calculateDiscount(1000, 10) + calculateDiscount(500, 10);
// Эквивалентно:
$total = 900 + 450; // 1350

Практическое применение в PHP:

  • Функции-хелперы для работы с данными (форматирование, валидация)
  • Бизнес-логика в Domain слое (DDD)
  • Функциональные преобразования в коллекциях
  • Сервисные классы без состояния

Ограничения: Не все можно сделать чистыми функциями — работа с БД, файлами, внешними API по определению имеет побочные эффекты. Ключ в изоляции "нечистых" операций и максимизации использования чистых функций для бизнес-логики.