Мемоизация
Оригинальное название: memoization
Коротко
Приём оптимизации: функция запоминает результат для каждого набора аргументов и при повторном вызове с теми же аргументами отдаёт сохранённое значение, ничего не вычисляя заново.
Что такое «Мемоизация»
Название происходит от английского memo — «памятка». Идею описал британский исследователь Дональд Мичи в 1968 году. Если функция вызывается много раз с одними и теми же данными, а считает долго, проще один раз записать ответ и дальше брать его из записи. Платить приходится памятью: таблица результатов растёт с каждым новым набором аргументов.
Условие: чистая функция
Мемоизировать можно только функцию, результат которой зависит исключительно от аргументов и которая ничего не меняет вокруг себя. Сумма двух чисел, расчёт доставки по весу и тарифу, разбор строки — подходят. Функция, которая читает текущее время, остатки со склада или курс валют, — нет: при тех же аргументах она должна возвращать новые данные, а мемоизация вернёт старые.
Пример на PHP
Классический случай — числа Фибоначчи. Наивная рекурсия пересчитывает одни и те же значения экспоненциальное число раз. Статический массив внутри функции живёт между вызовами и служит памяткой:
function fib(int $n): int
{
static $memo = [0 => 0, 1 => 1];
if (!isset($memo[$n])) {
$memo[$n] = fib($n - 1) + fib($n - 2);
}
return $memo[$n];
}
echo fib(80); // 23416728348467685
С памяткой каждое значение считается один раз, и ответ приходит мгновенно. Без неё вызов fib(80) не завершится за разумное время. В JavaScript-интерфейсах похожую задачу решают useMemo в React и вычисляемые свойства во Vue.
Мемоизация, кеш и transient — в чём разница
Мемоизация — частный случай кеша, привязанный к конкретной функции и её аргументам. Обычно она живёт в памяти одного процесса: в PHP — до конца обработки запроса. Общий кеш хранит любые данные и может переживать запросы. В WordPress для этого есть объектный кеш (wp_cache_get(), wp_cache_set()), а для данных со сроком жизни — transient, который сохраняется в базе или в Redis. Если результат нужен только внутри одного запроса, например функция вызывается из нескольких мест шаблона, хватает статической переменной. Если между запросами — нужен уже полноценный кеш с правилами сброса.

