首页 > PHP > Laravel教程 上下文

Laravel教程 上下文

2025-02-26 16:57:50

在 Laravel 中,上下文(Context) 类似于一种“共享数据空间”,允许你在不同代码层级(如控制器、中间件、服务类)之间传递或共享数据,而无需显式传递参数。


一、生活比喻理解上下文

1. 背包比喻:旅行中的共享物品

  • 场景:你和朋友一起旅行,共享一个背包,里面装着手电筒、地图、零食。每个人都可以随时从背包拿东西,无需反复传递。
  • 对应 Laravel:上下文就像这个背包,存储全局可访问的数据(如用户信息、请求标识),任何地方都能获取。

2. 快递包裹:层层传递的订单号

  • 场景:快递从收件到派送,包裹上的订单号始终存在,每个环节都能读取。
  • 对应 Laravel:中间件、控制器、服务类共享同一个请求的上下文(如请求ID)。

3. 餐厅餐桌:当前桌的订单

  • 场景:服务员处理某一桌订单时,只需知道桌号,无需关心其他桌。
  • 对应 Laravel:每个请求的上下文隔离(如多租户系统的租户ID)。

二、Laravel 上下文的实现方式

1. 服务容器(Service Container)绑定

  • 作用:将对象或值绑定到容器,全局可获取。
  • 代码示例
    // 在服务提供者中绑定数据
    app()->bind('shared.data', function () {
        return ['request_id' => uniqid()];
    });
    
    // 在控制器中获取
    $sharedData = app('shared.data');
    

2. Request 实例传递数据

  • 适用场景:在中间件设置数据,后续流程直接读取。
  • 代码示例
    // 中间件中设置数据
    class SetRequestContext
    {
        public function handle($request, $next) {
            $request->merge(['request_id' => uniqid()]);
            return $next($request);
        }
    }
    
    // 控制器中读取
    public function index(Request $request) {
        echo $request->input('request_id'); // 输出唯一ID
    }
    

3. 使用 Context 类(Laravel 8+)

  • 特性:专为协程或异步任务设计,隔离不同请求的上下文。
  • 代码示例
    use Illuminate\Support\Facades\Context;
    
    // 设置上下文数据
    Context::set('user.id', auth()->id());
    
    // 获取数据
    $userId = Context::get('user.id');
    

4. 全局辅助函数 session() 或 cache()

  • 注意:会话和缓存是持久化存储,上下文通常是临时共享。
  • 示例
    // 设置临时数据(不推荐长期存储)
    session()->now('flash_message', '操作成功!');
    
    // 视图直接读取
    <div>{{ session('flash_message') }}</div>
    

三、实际场景示例:跟踪请求生命周期

目标:记录某个请求在所有日志中的唯一ID

  1. 中间件生成请求ID

    // app/Http/Middleware/AssignRequestId.php
    public function handle($request, $next) {
        $requestId = uniqid();
        app()->instance('request_id', $requestId); // 绑定到容器
        Context::set('request_id', $requestId);    // 或使用上下文类
        return $next($request);
    }
    
  2. 控制器中使用

    public function show() {
        $requestId = app('request_id');
        Log::info("Controller处理请求ID: $requestId");
    }
    
  3. 服务类中调用

    class PaymentService {
        public function charge() {
            $requestId = Context::get('request_id');
            Log::debug("支付服务请求ID: $requestId");
        }
    }
    

四、注意事项

  1. 避免滥用:过度依赖全局上下文会导致代码耦合。
  2. 生命周期管理:明确上下文数据的有效期(如仅限当前请求)。
  3. 并发安全:异步或队列任务中,使用 Context 类确保隔离性。
 

 

使用 Ctrl+D 可将网站添加到书签
收藏网站
扫描二维码
关注早实习微信公众号
官方公众号
Top