Challenge 3 — Solution Task: Write a function getCachedOrCompute(string $cacheFile, int $ttlSeconds, callable $computeFn) that generalises the chapter's file-cache example — if a fresh cache file exists, return its decoded contents; otherwise call $computeFn(), cache its result, and return it. Show it being used to cache the result of an expensive function getExpensiveReport(). 45230, 'top_product' => 'Widget Pro']; } $report = getCachedOrCompute('/tmp/expensive_report_cache.json', 300, 'getExpensiveReport'); print_r($report); ?> Output (first call, no cache file exists yet): (a real 3-second delay while getExpensiveReport() actually runs) Array ( [total_sales] => 45230 [top_product] => Widget Pro ) Output (a second call within 300 seconds of the first): (returns instantly — no 3-second delay — since the cache file is still fresh) Array ( [total_sales] => 45230 [top_product] => Widget Pro ) Notes: - getCachedOrCompute() generalises the chapter's own getPopularPosts() example by accepting the compute logic itself as a callable parameter, rather than hardcoding one specific database query inside the caching function - the same underlying pattern now works for any expensive operation, not just this one. - 'getExpensiveReport' is passed as a string here, which PHP recognizes as a callable function name and invokes correctly via $computeFn() - an anonymous function or a [$object, 'method'] array would work identically, since callable accepts any of PHP's several callable shapes. - The caching logic itself - checking file_exists() and comparing filemtime() against the TTL - is copied directly from the chapter's own getPopularPosts() example, just decoupled from any one specific piece of data or computation.