wp_cache_get with the found flag

A cached value of false and a cache miss both return false, so a lookup that legitimately caches “no result” re-queries on every request and the cache appears not to work.

$found = false;
$value = wp_cache_get( $key, 'shop', false, $found );

if ( ! $found ) {
    $value = $this->expensiveLookup();
    wp_cache_set( $key, $value, 'shop', HOUR_IN_SECONDS );
}

The fourth parameter is by reference and is the only way to distinguish the two. This matters most for negative caching, which is exactly where the expensive lookup is — a product that does not exist is looked up as often as one that does, and without the flag it is never cached. Transients have the same problem and no equivalent flag, which is one reason to prefer the object cache API here.