PHP 怎么上下文传递

wen PHP项目 2

本文目录导读:

PHP 怎么上下文传递

  1. use 关键字(闭包/匿名函数)
  2. 依赖注入(构造函数/方法注入)
  3. 全局变量(不推荐,但有特殊用途)
  4. 静态属性/服务容器
  5. 魔术方法 __invoke 和闭包
  6. Generators 上下文传递
  7. 现代框架中的上下文(PSR-11 容器)
  8. 最佳实践建议
  9. 完整示例:用户认证上下文

在 PHP 中,上下文传递(Context Passing)主要有以下几种方式,我会逐一详细说明:

use 关键字(闭包/匿名函数)

最常用的上下文传递方式,用于在闭包中捕获外部变量:

<?php
$userId = 123;
$userName = "Alice";
// 基本使用
$greeting = function() use ($userId, $userName) {
    return "User {$userId}: {$userName}";
};
echo $greeting(); // 输出: User 123: Alice
// 按引用传递
$counter = 0;
$increment = function() use (&$counter) {
    $counter++;
};
$increment();
$increment();
echo $counter; // 输出: 2
// 捕获对象
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$query = function($sql) use ($db) {
    return $db->query($sql);
};
?>

依赖注入(构造函数/方法注入)

通过构造函数或方法参数传递上下文:

<?php
class UserService
{
    private $db;
    private $logger;
    public function __construct(PDO $db, Logger $logger)
    {
        $this->db = $db;
        $this->logger = $logger;
    }
    public function getUser($id)
    {
        $this->logger->info("Getting user: $id");
        // 使用 $this->db
    }
}
// 实例化时传递依赖
$db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$logger = new FileLogger('/var/log/app.log');
$service = new UserService($db, $logger);
?>

全局变量(不推荐,但有特殊用途)

<?php
// 全局配置
$GLOBALS['config'] = [
    'db_host' => 'localhost',
    'db_name' => 'test',
    'debug' => true
];
// 全局错误处理器
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    global $GLOBALS;
    error_log($errstr, 3, $GLOBALS['config']['log_file']);
}
// 全局变量访问(尽量避免)
$config = $GLOBALS['config'];
echo $config['db_host'];
?>

静态属性/服务容器

使用静态属性或服务容器模式:

<?php
class AppContext
{
    private static $instance = null;
    private $db;
    private $user;
    private $session;
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function setDb($db)
    {
        $this->db = $db;
        return $this;
    }
    public function getDb()
    {
        return $this->db;
    }
    public function setUser($user)
    {
        $this->user = $user;
        return $this;
    }
    public function getUser()
    {
        return $this->user;
    }
}
// 使用
AppContext::getInstance()
    ->setDb($db)
    ->setUser($currentUser);
// 在任何地方获取
$user = AppContext::getInstance()->getUser();
?>

魔术方法 __invoke 和闭包

<?php
class ContextHandler
{
    private $context;
    public function __invoke($data)
    {
        // 使用上下文处理数据
        if ($this->context['debug']) {
            var_dump($data);
        }
        return $this->processWithContext($data);
    }
    private function processWithContext($data)
    {
        // 使用 $this->context 逻辑
        return $data;
    }
}
$handler = new ContextHandler();
$handler->context = ['debug' => true, 'app' => 'MyApp'];
// 直接调用
$result = $handler(['key' => 'value']);
?>

Generators 上下文传递

<?php
function processItems($items, $context = []) {
    foreach ($items as $item) {
        // 使用上下文
        yield $context['prefix'] . $item;
    }
}
$items = ['apple', 'banana', 'orange'];
$context = ['prefix' => 'fruit: '];
foreach (processItems($items, $context) as $processed) {
    echo $processed . PHP_EOL;
}
?>

现代框架中的上下文(PSR-11 容器)

使用 PSR-11 依赖注入容器:

<?php
// 使用容器接口
interface ContainerInterface
{
    public function get($id);
    public function has($id);
}
class MyContainer implements ContainerInterface
{
    private $services = [];
    public function get($id)
    {
        if (!$this->has($id)) {
            throw new Exception("Service not found: $id");
        }
        return $this->services[$id]();
    }
    public function set($id, $factory)
    {
        $this->services[$id] = $factory;
        return $this;
    }
    public function has($id)
    {
        return isset($this->services[$id]);
    }
}
// 使用
$container = new MyContainer();
$container->set('db', function() {
    return new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
});
// 获取服务
$db = $container->get('db');
?>

最佳实践建议

  1. 优先使用依赖注入:让类显式声明依赖
  2. 避免全局变量:会增加耦合度,难以测试
  3. 使用容器管理复杂依赖:在大型应用中使用
  4. 闭包捕获注意性能:大量使用闭包捕获可能影响性能
  5. 考虑作用域:明确变量在何处被使用

完整示例:用户认证上下文

<?php
// 定义 UserContext 类
class UserContext
{
    private $user;
    private $roles;
    private $ip;
    private $session;
    public function __construct($user, $session, $ip) {
        $this->user = $user;
        $this->session = $session;
        $this->ip = $ip;
    }
    public function getUser() { return $this->user; }
    public function hasRole($role) { return in_array($role, $this->roles); }
    public function getIp() { return $this->ip; }
}
// 在框架中传递
class RequestHandler {
    public function handle(Request $request, UserContext $userContext) {
        if ($userContext->hasRole('admin')) {
            // 管理员逻辑
        } else {
            // 普通用户逻辑
        }
    }
}
// 创建上下文
$context = new UserContext($user, $session, $request->getClientIp());
$handler = new RequestHandler();
$handler->handle($request, $context);
?>

选择合适的上下文传递方式取决于:

  • 应用规模和复杂度
  • 测试难度要求
  • 代码可维护性
  • 性能需求

通常推荐组合使用多种方式,但要有明确的设计原则。

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