Laravel's Context API introduces powerful remember() and rememberHidden() methods that streamline request-scoped data management through elegant closure-based memoization. These functions optimize expensive computations across your application with clean, expressive syntax.
The remember() function provides automatic memoization within the request context:
use Illuminate\Support\Facades\Context; $roles = Context::remember('user-roles', fn() => $this->calculateUserRoles(auth()->user()));
This method automatically manages the existence check and computation cycle, executing the closure only when the context key is absent.
Consider a multi-service architecture where request-scoped data like organization settings, access controls, and feature configurations must be shared efficiently across various application layers. These values are computationally expensive but frequently accessed throughout the request lifecycle:
<?php namespace App\Services; use Illuminate\Support\Facades\Context;use Illuminate\Support\Facades\DB;use App\Models\Organization;use App\Models\User; class OrganizationContextService{ public function getOrganizationSettings(): array { return Context::remember('org-settings', function () { $organization = $this->getCurrentOrganization(); return [ 'subscription_tier' => $this->getSubscriptionTier($organization), 'enabled_modules' => $this->getEnabledModules($organization), 'user_limits' => $this->getUserLimits($organization), 'integration_settings' => $this->getIntegrationSettings($organization), ]; }); } public function getCurrentUserAccessLevel(): array { return Context::remember('user-access-level', function () { $user = auth()->user(); $organization = $this->getCurrentOrganization(); $directPermissions = $user->permissions() ->where('organization_id', $organization->id) ->pluck('action') ->toArray(); $groupPermissions = $user->groups() ->with('permissions') ->get() ->flatMap(fn($group) => $group->permissions) ->pluck('action') ->toArray(); $inheritedPermissions = $this->calculateInheritedPermissions($user, $organization); return array_unique(array_merge( $directPermissions, $groupPermissions, $inheritedPermissions )); }); } public function getSecureCredentials(): array { return Context::rememberHidden('secure-credentials', function () { $organization = $this->getCurrentOrganization(); return [ 'api_secret' => decrypt($organization->encrypted_api_secret), 'webhook_token' => $this->generateWebhookToken($organization), 'internal_key' => $this->getInternalEncryptionKey($organization), ]; }); } public function hasFeatureAccess(string $feature): bool { $settings = $this->getOrganizationSettings(); $userAccess = $this->getCurrentUserAccessLevel(); return in_array($feature, $settings['enabled_modules']) && in_array("feature:{$feature}", $userAccess); } protected function getCurrentOrganization(): Organization { return Context::remember('current-organization', function () { $subdomain = request()->route('organization') ?? request()->getHost(); return Organization::where('subdomain', $subdomain) ->with(['subscription', 'settings']) ->firstOrFail(); }); } protected function getSubscriptionTier(Organization $organization): string { return $organization->subscription->tier ?? 'basic'; } protected function getEnabledModules(Organization $organization): array { $baseTier = $this->getSubscriptionTier($organization); $customModules = $organization->settings->pluck('module')->toArray(); return array_merge( $this->getDefaultModulesForTier($baseTier), $customModules ); } protected function getUserLimits(Organization $organization): array { $tier = $this->getSubscriptionTier($organization); return match($tier) { 'enterprise' => ['max_users' => -1, 'storage_gb' => 1000], 'professional' => ['max_users' => 100, 'storage_gb' => 100], 'basic' => ['max_users' => 10, 'storage_gb' => 10], default => ['max_users' => 5, 'storage_gb' => 1], }; } protected function getIntegrationSettings(Organization $organization): array { return $organization->integrations() ->where('active', true) ->get() ->mapWithKeys(fn($integration) => [ $integration->service => $integration->configuration ]) ->toArray(); } protected function calculateInheritedPermissions(User $user, Organization $organization): array { if ($user->is_organization_owner) { return ['admin:*', 'user:*', 'billing:*', 'settings:*']; } if ($user->is_manager) { return ['user:manage', 'reports:view', 'settings:view']; } return ['profile:edit', 'dashboard:view']; } protected function generateWebhookToken(Organization $organization): string { return hash_hmac('sha256', $organization->id . now()->timestamp, config('app.key')); } protected function getInternalEncryptionKey(Organization $organization): string { return hash('sha256', config('app.key') . $organization->uuid); } protected function getDefaultModulesForTier(string $tier): array { return match($tier) { 'enterprise' => ['analytics', 'integrations', 'advanced_reports', 'api_access'], 'professional' => ['analytics', 'basic_reports', 'limited_api'], 'basic' => ['dashboard', 'basic_reports'], default => ['dashboard'], }; }} class ReportingController extends Controller{ public function __construct( private OrganizationContextService $contextService ) {} public function generateReport(Request $request) { if (!$this->contextService->hasFeatureAccess('advanced_reports')) { abort(403, 'Advanced reporting not available for current plan'); } $settings = $this->contextService->getOrganizationSettings(); $userAccess = $this->contextService->getCurrentUserAccessLevel(); return view('reports.advanced', compact('settings', 'userAccess')); } public function exportData(Request $request) { $credentials = $this->contextService->getSecureCredentials(); if (!$this->verifyExportPermissions($credentials['internal_key'])) { abort(401, 'Invalid export permissions'); } return $this->processDataExport($request); }}
The remember() function ensures expensive operations like permission calculations and organization lookups execute only once per request, regardless of access frequency. The rememberHidden() variant maintains identical caching behavior while excluding sensitive data from log entries, making it ideal for credentials and security tokens.
This pattern excels in middleware layers, service dependencies, and view composers where identical context data requires multiple access points. The closure-based design creates self-documenting code that clearly indicates the computation triggered during cache misses.