本文目录导读:

- use 关键字(闭包/匿名函数)
- 依赖注入(构造函数/方法注入)
- 全局变量(不推荐,但有特殊用途)
- 静态属性/服务容器
- 魔术方法 __invoke 和闭包
- Generators 上下文传递
- 现代框架中的上下文(PSR-11 容器)
- 最佳实践建议
- 完整示例:用户认证上下文
在 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');
?>
最佳实践建议
- 优先使用依赖注入:让类显式声明依赖
- 避免全局变量:会增加耦合度,难以测试
- 使用容器管理复杂依赖:在大型应用中使用
- 闭包捕获注意性能:大量使用闭包捕获可能影响性能
- 考虑作用域:明确变量在何处被使用
完整示例:用户认证上下文
<?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);
?>
选择合适的上下文传递方式取决于:
- 应用规模和复杂度
- 测试难度要求
- 代码可维护性
- 性能需求
通常推荐组合使用多种方式,但要有明确的设计原则。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播