Generic memoize utility function for pure functions

Code Review Asked by Ngoy Lufo on December 12, 2020

Given the following generic memoize utility for pure functions with type hints:

function memoize(callable $fn, callable $serialize = null): callable {
    $serialize = $serialize ? $serialize : 'serialize';

    return function(...$args) use ($fn, $serialize) {
        static $cache = [];
        $k = $serialize($args);
        return isset($cache[$k]) ? $cache[$k] : ($cache[$k] = $fn(...$args));

Is the callable type hint here preferred as opposed to closure? I’m also not sure if I’m being too pedantic with the type hints and whether my use of static here is recommended?

I’d appreciate any feedback on the code above.

One Answer

To address your first question:

Is the callable type hint here preferred as opposed to closure?

There is a very similar question on StackOverflow: PHP: Type hinting - Difference between Closure and Callable. It has three answers.

The first line of the answer by Xorifelse explains:

The main difference between them is that a closure is a class and callable a type.

And the last line of the accepted answer by Rizier123 has this suggestion:

So if you only want to type hint anonymous function use: Closure and if you want also to allow normal functions use callable as type hint.

And now, for something completely different general code review comments:

Variable naming

The name $k is a little too brief... $key isn't very long and describes what the variable is.

Simplifying ternary expressions

Correct me if I am mistaken but as long as PHP 5.3+ is used then this line:

$serialize = $serialize ? $serialize : 'serialize';

could be shortened using the fact that:

The expression (expr1) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to TRUE, and expr3 if expr1 evaluates to FALSE.
Since PHP 5.3, it is possible to leave out the middle part of the ternary operator. Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.1

to the following:

$serialize = $serialize ?: 'serialize';

If PHP 7+ is used (which hopefully is the case, since at the time of writing, 7.2+ are actively maintained2) then the null coalescing operator i.e. ?? could also be used to simplify cases where a fallback should be used if a non-null value does not exist - e.g. :

 return isset($cache[$k]) ? $cache[$k] : ($cache[$k] = $fn(...$args));

Can become:

return $cache[$k] ?? ($cache[$k] = $fn(...$args));

Correct answer by Sᴀᴍ Onᴇᴌᴀ on December 12, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP