Laravel Laravel
  • 序章

    • 发布说明
    • 升级指南
    • 贡献指南
  • 快速开始

    • 安装
    • 配置
    • 目录结构
    • 前端
    • 入门套件
    • 部署
  • 架构概念

    • 请求生命周期
    • 服务容器
    • 服务提供者
    • 门面
  • 基础

    • 路由
    • 中间件
    • CSRF 保护
    • 控制器
    • 请求
    • 响应
    • 视图
    • Blade 模板
    • 资源打包
    • URL 生成
    • 会话
    • 验证
    • 错误处理
    • 日志记录
  • 深入探讨

    • Artisan 控制台
    • 广播
    • 缓存
    • 集合
    • 并发
    • 上下文
    • 契约
    • 事件
    • 文件存储
    • 辅助函数
    • HTTP 客户端
    • 本地化
    • 邮件
    • 通知
    • 包开发
    • 进程
    • 队列
    • 速率限制
    • 字符串
    • 任务调度
  • 安全

    • 认证
    • 授权
    • 邮件验证
    • 加密
    • 哈希
    • 密码重置
  • 数据库

    • 快速开始
    • 查询构建器
    • 分页
    • 迁移
    • 数据填充
    • Redis
    • MongoDB
  • Eloquent ORM

    • 快速开始
    • 关系
    • 集合
    • 变换器/类型转换
    • API 资源
    • 序列化
    • 工厂
  • 测试

    • 快速开始
    • HTTP 测试
    • 控制台测试
    • 浏览器测试
    • 数据库测试
    • Mock 测试
  • 软件包

    • Breeze
    • Cashier(Stripe)
    • Cashier(Paddle)
    • Dusk
    • Envoy
    • Fortify
    • Folio
    • Homestead
    • Horizon
    • Jetstream
    • Mix
    • Octane
    • Passport
    • Pennant
    • Pint
    • Precognition
    • Prompts
    • Pulse
    • Reverb
    • Sail
    • Sanctum
    • Scout
    • Socialite
    • Telescope
    • Valet
  • API 文档

Context 上下文
点赞
0
11.x
11.x 10.x 9.x 8.5 8.x 7.x 6.x 5.8 5.7 5.6 5.5 5.4 5.3 5.2 5.1

Laravel 11 中文文档 /

未匹配的标注
本文档最新版为 10.x,旧版本可能放弃维护,推荐阅读最新版!

Context 上下文

  • 介绍
    • 工作原理
  • 捕获 Context 上下文
    • 堆栈
  • 检索 Context 上下文
    • 确定项目是否存在
  • 移除 Context 上下文
  • 隐藏 Context 上下文
  • 事件
    • 脱水
    • 注水

介绍

Laravel 的「Context 上下文」功能使你能够在应用程序中执行的请求、任务和命令中捕获、检索和共享信息。这些捕获的信息也包含在应用程序写入的日志中,使你深入了解在写入日志条目之前发生的代码执行历史,并允许你跟踪整个分布式系统的执行流程。

工作原理

理解 Laravel Context 上下文功能的最佳方式是使用内置的日志功能来观察它的实际情况。首先,你可以使用 Context Facade 向 Context 上下文添加信息。在此示例中,我们将使用 中间件 将请求 URL 和唯一的跟踪 ID 添加到每个传入请求的 Context 上下文中:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;

class AddContext
{
    /**
     * 处理传入的请求
     */
    public function handle(Request $request, Closure $next): Response
    {
        Context::add('url', $request->url());
        Context::add('trace_id', Str::uuid()->toString());

        return $next($request);
    }
}

添加到 Context 上下文中的信息会自动作为元数据附加到在请求期间写入的任何 日志条目 中。将 Context 上下文作为元数据附加到日志条目中,可以将传递到单个日志条目的信息与通过 Context 共享的信息区分开来。例如,假设我们写入以下日志条目:

Log::info('User authenticated.', ['auth_id' => Auth::id()]);

写入的日志将包含传递给日志条目的 auth_id,但也将包含上下文的 url 和 trace_id 作为元数据:

User authenticated. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

添加到上下文的信息也可用于分发到队列的任务。比如,假设我们在将一些信息添加到上下文后,将 ProcessPodcast 任务分发给队列:

// 在中间件中...
Context::add('url', $request->url());
Context::add('trace_id', Str::uuid()->toString());

// 在控制器中...
ProcessPodcast::dispatch($podcast);

任务分发时,当前保存在上下文中的所有信息,都可以在任务中捕获和分享。然后,在执行任务时,这些捕获的信息填充回到当前上下文中。因此,如果我们的任务的 handle 方法是写入日志:

class ProcessPodcast implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    // ...

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('Processing podcast.', [
            'podcast_id' => $this->podcast->id,
        ]);

        // ...
    }
}

生成的日志条目将包含在最初调度该任务的请求期间添加到上下文中的信息:

Processing podcast. {"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"}

尽管我们关注的是 Laravel 上下文的内置日志相关功能,但后续文档将说明上下文如何允许跨 HTTP 请求/队列任务边界共享信息,甚至如何添加未使用日志条目编写的隐藏上下文数据。

捕获上下文

使用 Context 门面的 add 方法,你可以在当前上下文中存储信息:

use Illuminate\Support\Facades\Context;

Context::add('key', 'value');

要一次添加多个项目,你可以将关联数组传递给 add 方法:

Context::add([
    'first_key' => 'value',
    'second_key' => 'value',
]);

该 add 方法将覆盖共享同一个键名的现有值。如果你只想将还不存在键名的信息添加到上下文中,你可以使用 addIf 方法:

Context::add('key', 'first');

Context::get('key');
// "first"

Context::addIf('key', 'second');

Context::get('key');
// "first"

条件上下文

when 方法可以用于基于给定条件将数据添加到上下文中。如果给定的条件等于 true,when 方法中的第一个闭包将被调用;而如果给定的条件等于 false,则会调用第二个闭包:

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Context;

Context::when(
    Auth::user()->isAdmin(),
    fn ($context) => $context->add('permissions', Auth::user()->permissions),
    fn ($context) => $context->add('permissions', []),
);

堆栈

上下文提供了创建「堆栈」的能力,堆栈是按添加顺序存储的数据列表。你可以通过调用 push 方法将信息添加到堆栈中:

use Illuminate\Support\Facades\Context;

Context::push('breadcrumbs', 'first_value');

Context::push('breadcrumbs', 'second_value', 'third_value');

Context::get('breadcrumbs');
// [
//     'first_value',
//     'second_value',
//     'third_value',
// ]

堆栈可用于捕获有关请求的历史信息,例如整个应用中发生的事件。比如,你可以创建一个事件监听器,以便在每次执行查询时推送到堆栈,将查询 SQL 和持续时间捕获为元组:

use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\DB;

DB::listen(function ($event) {
    Context::push('queries', [$event->time, $event->sql]);
});

检索上下文

你可以使用 Context 门面的 get 方法,从上下文中检索信息:

use Illuminate\Support\Facades\Context;

$value = Context::get('key');

only 方法可用于在上下文中检索信息子集。

$data = Context::only(['first_key', 'second_key']);

pull 方法可用于从上下文中检索信息并立即将其从上下文中删除:

$value = Context::pull('key');

如果你想检上下文中存储的所有信息,你可以调用 all 方法:

$data = Context::all();

检查项目是否存在

你可以使用 has 方法检测上下文是否为给定的键存有任何值:

use Illuminate\Support\Facades\Context;

if (Context::has('key')) {
    // ...
}

不管存储的值是什么,has 方法都将返回 true。因此,比如,具有 null 值的键将被视为存在:

Context::add('key', null);

Context::has('key');
// true

删除上下文

forget 方法可用于在当前上下文中删除键及它的值:

use Illuminate\Support\Facades\Context;

Context::add(['first_key' => 1, 'second_key' => 2]);

Context::forget('first_key');

Context::all();

// ['second_key' => 2]

通过给 forget 方法提供一个数组,你可以一次性删除多个键:

Context::forget(['first_key', 'second_key']);

隐藏上下文

上下文提供存储隐藏数据的能力。这些隐藏信息不会追加到日志中,也无法通过上述数据检索方法进行访问。上下文提供了一组不同的方法来与隐藏的上下文信息交互:

use Illuminate\Support\Facades\Context;

Context::addHidden('key', 'value');

Context::getHidden('key');
// 'value'

Context::get('key');
// null

这些「隐藏」方法对上述非隐藏方法的功能进行了镜像:

Context::addHidden(/* ... */);
Context::addHiddenIf(/* ... */);
Context::pushHidden(/* ... */);
Context::getHidden(/* ... */);
Context::pullHidden(/* ... */);
Context::onlyHidden(/* ... */);
Context::allHidden(/* ... */);
Context::hasHidden(/* ... */);
Context::forgetHidden(/* ... */);

事件

上下文分发了两个事件,允许你插入钩子到上下文的注水和脱水处理过程。

为了说明如何使用这些事件,假设在应用的中间件中,你根据传入的HTTP 请求的 Accept Language 标头设置 app.locate 配置值。上下文的事件允许你在请求期间捕获此值并将其还原到队列中,从而确保在队列上发送的通知具有正确的 app.locale 值。我们可以使用上下文的事件和隐藏的 数据来实现这一点,下面的文档将对此进行说明。

脱水

每当任务被调度到队列时,上下文中的数据都会被「脱水」,并与任务业的有效负载一起捕获。Context::dehydrating 方法允许你对将在脱水过程中调用的闭包进行注册。在此闭包中,你可以对将与队列任务共享的数据进行更改。

通常,你应该在应用的 AppServiceProvider 类的 boot 方法中注册 dehydrating 回调:

use Illuminate\Log\Context\Repository;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Context;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Context::dehydrating(function (Repository $context) {
        $context->addHidden('locale', Config::get('app.locale'));
    });
}

注意
你不应在 dehydrating 回调中使用 Context 门面,因为这会将修改当前进程的上下文。请确保仅对传递给回调的存储库进行更改。

注水

每当队列中的任务开始在队列上执行时,与该任务共享的任何上下文都将注水回当前上下文。Context::hydrated 方法允许你注册将在注水过程中调用的闭包。

通常,你应该在应用的 AppServiceProvider 类中的 boot 方法里注册 hydrated 回调:

use Illuminate\Log\Context\Repository;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Context;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Context::hydrated(function (Repository $context) {
        if ($context->hasHidden('locale')) {
            Config::set('app.locale', $context->getHidden('locale'));
        }
    });
}

注
你不应在hydrated 回调中使用 Context 门面,并请确保仅对传递给回调的存储库进行更改。

本文章首发在 网站上。



原文地址:cndocs/11.x/co...

译文地址:cndocs/11.x/co...

上一篇 下一篇

成为Laravel合作伙伴

Laravel Partners是提供一流Laravel开发和咨询服务的精英商店。我们每个合作伙伴都可以帮助您制定一个精美,结构完善的项目.

我们的伙伴
Laravel
亮点
  • Our Team
  • 发布说明
  • 入门
  • 路由
  • Blade 模板
  • 身份验证
  • 用户授权
  • Artisan 控制台
  • 数据库
  • Eloquent ORM
  • 测试
资源
  • Laravel Bootcamp
  • Laracasts
  • Laravel News
  • Laracon
  • Laracon EU
  • Laracon India
  • Jobs
  • Forums
  • Trademark
  • 版本发布时间
  • 包开发
  • 命令行应用
  • TALL stack全栈开发
  • Blade UI Kit
  • 前端资源构建
伙伴
  • WebReinvent
  • Vehikl
  • Tighten
  • 64 Robots
  • Active Logic
  • Byte 5
  • Curotec
  • Cyber-Duck
  • DevSquad
  • Jump24
  • Kirschbaum
生态系统
  • Cashier
  • Dusk
  • Echo
  • Envoyer
  • Forge
  • Horizon
  • Nova
  • Octane
  • Sail
  • Sanctum
  • Scout
  • Spark
  • Telescope
  • Valet
  • Vapor

Laravel是一个具有表达力,优雅语法的Web应用程序框架。我们认为,发展必须是一种令人愉悦的创造力,才能真正实现。Laravel试图通过减轻大多数Web项目中使用的常见任务来减轻开发的痛苦.

Laravel是Taylor Otwell的商标.
Copyright © 2011-2025 Laravel中文网 LLC.

  • Twitter
  • GitHub
  • Discord
Laravel 全栈开发网 推荐使用阿里云 按Ctrl+D试试