由于同一个进程内协程间是内存共享的,但协程的执行/切换是非顺序的,也就意味着我们很难掌控当前的协程是哪一个(事实上可以,但通常没人这么干),所以我们需要在发生协程切换时能够同时切换对应的上下文。
以 hyperf 2.2
版本为例
实例
错误用法
使用成员变量来存储变量
<?php
/**
* Message.php
*
* Created on Message-15:28
* Created by xxp 332410549@qq.com
*/
namespace App\Controller;
use Hyperf\Di\Container;
use Hyperf\HttpServer\Annotation\AutoController;
use App\Controller\AbstractController;
use Hyperf\HttpServer\Annotation\Middleware;
use App\Middleware\Auth\FooMiddleware;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Context;
/**
* @AutoController()
*/
class MessageController extends AbstractController
{
public $name = 'xie';
public function index()
{
return 'message';
}
/**
* @return ContainerInterface
*/
public function requests(RequestInterface $request)
{
$name = $request->input('name');
$this->name = $name;
return $name;
}
public function test(RequestInterface $request){
$name = $request->input('name');
if (empty($name)){
return 'name is empty';
}
return $this->name;
}
}
把name=wang
放到类的成员变量里
获取name的值,是wang,因为hyperf 是一个长连接请求,每个请求是不同的协程来实现,但是这第两个请求,获取的是第一个设置的值,但是他们又是不同的协程,本不该从一个协程获取另一个协程的数据,说明数据混淆了
正确用法
使用上下文来存储变量
class MessageController extends AbstractController
{
public function index()
{
return 'message';
}
/**
* @return ContainerInterface
*/
public function requests(RequestInterface $request)
{
$name = $request->input('name');
Context::set('name', $name);
return $name;
}
public function test(RequestInterface $request){
$name = $request->input('name');
if (empty($name)){
return 'name is empty';
}
return Context::get($name,'xie');
}
}
把name=wang
放到上下文里
获取name的值,不是wang,而是默认值xie, 说明他们是不同的协程请求,数据被隔离