PHP 请求上下文怎么共享

wen PHP项目 2

本文目录导读:

PHP 请求上下文怎么共享

  1. 超全局变量(最常用)
  2. 全局变量(谨慎使用)
  3. 静态属性(推荐方式)
  4. 依赖注入容器(框架实现)
  5. 使用单例模式
  6. 文件或 Redis 缓存(跨请求)
  7. 最佳实践建议
  8. 注意事项

在 PHP 中,请求上下文的共享有几种方式,让我详细说明:

超全局变量(最常用)

$_GET, $_POST, $_REQUEST

// 请求参数共享
function getUserInput() {
    // 可以在任何函数中访问
    return $_POST['username'] ?? $_GET['username'] ?? '';
}

$_SESSION - 会话级共享

// 设置
session_start();
$_SESSION['user_id'] = 123;
// 在其他请求中读取
function getCurrentUser() {
    session_start();
    return $_SESSION['user_id'] ?? null;
}

$_COOKIE - Cookie 共享

// 设置 Cookie
setcookie('theme', 'dark', time() + 3600);
// 读取
$theme = $_COOKIE['theme'] ?? 'light';

全局变量(谨慎使用)

// 使用 global 关键字
$appContext = [];
function setContext($key, $value) {
    global $appContext;
    $appContext[$key] = $value;
}
function getContext($key) {
    global $appContext;
    return $appContext[$key] ?? null;
}

静态属性(推荐方式)

class Context {
    private static array $data = [];
    private static ?User $currentUser = null;
    public static function set($key, $value) {
        self::$data[$key] = $value;
    }
    public static function get($key) {
        return self::$data[$key] ?? null;
    }
    public static function setUser(User $user) {
        self::$currentUser = $user;
    }
    public static function getUser(): ?User {
        return self::$currentUser;
    }
}
// 使用
Context::setUser($user);
Context::set('request_id', uniqid());

依赖注入容器(框架实现)

// 简单容器实现
class Container {
    private array $instances = [];
    public function set($key, $instance) {
        $this->instances[$key] = $instance;
    }
    public function get($key) {
        return $this->instances[$key] ?? null;
    }
}
// 初始化
$container = new Container();
$container->set('db', new PDO(...));
$container->set('logger', new Logger());
// 通过构造函数注入
class UserService {
    private Container $container;
    public function __construct(Container $container) {
        $this->container = $container;
    }
    public function getDb() {
        return $this->container->get('db');
    }
}

使用单例模式

class AppContext {
    private static ?self $instance = null;
    private array $data = [];
    private function __construct() {}
    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function set($key, $value) {
        $this->data[$key] = $value;
    }
    public function get($key) {
        return $this->data[$key] ?? null;
    }
}
// 使用
$context = AppContext::getInstance();
$context->set('request_time', microtime(true));

文件或 Redis 缓存(跨请求)

// Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->set('user_' . $userId, json_encode($userData), 3600);
$user = json_decode($redis->get('user_' . $userId), true);
// 文件
$cacheFile = '/tmp/cache_' . $userId . '.json';
file_put_contents($cacheFile, json_encode($userData));
$user = json_decode(file_get_contents($cacheFile), true);

最佳实践建议

class RequestContext {
    private static array $context = [];
    // 初始化请求上下文
    public static function init(array $config = []) {
        self::$context = [
            'request_id' => uniqid(),
            'start_time' => microtime(true),
            'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
            'config' => $config,
        ];
    }
    public static function set($key, $value) {
        self::$context[$key] = $value;
    }
    public static function get($key, $default = null) {
        return self::$context[$key] ?? $default;
    }
    public static function all() {
        return self::$context;
    }
}
// 入口文件初始化
RequestContext::init(['debug' => true]);
RequestContext::set('user_id', 123);
// 业务代码中使用
function processRequest() {
    $requestId = RequestContext::get('request_id');
    $userId = RequestContext::get('user_id');
    // 处理逻辑...
}

注意事项

  1. FPM 模式下:每个请求是独立的进程,全局变量不会跨请求共享
  2. 避免过度使用全局状态:会增加代码耦合度
  3. 使用框架:如 Laravel 的 Request 门面、服务容器等
  4. 考虑线程安全:在使用共享数据时要注意并发问题
  5. 清理资源:请求结束后及时清理临时数据

选择哪种方式取决于你的具体场景和项目架构,对于小项目,超全局变量和静态属性就足够了;对于大型项目,建议使用依赖注入容器。

抱歉,评论功能暂时关闭!