<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
/**
* @AutoController()
*/
class CoController{
private $foo = 1;
public function get(){
return $this->foo;
}
public function update(RequestInterface $request){
$foo = $request -> input('foo');
$this->foo = $foo;
return $this->foo;
}
}
get 返回的是1 这一步是对的
第二步 更新值返回更新值是2 也是对的
第三步 设想是返回1 但是返回的是2
单例对不同请求的影响 怎么处理这种情况往下看
处理过程
处理方法一:协程上下文
由于同一个进程内协程间是内存共享的,但协程的执行/切换是非顺序的,也就意味着我们很难掌控当前的协程是哪一个*(事实上可以,但通常没人这么干)*,所以我们需要在发生协程切换时能够同时切换对应的上下文。
在 Hyperf 里实现协程的上下文管理将非常简单,基于 Hyperf\Utils\Context 类的 set(string $id, $value)、get(string $id, $default = null)、has(string $id)、override(string $id, \Closure $closure) 静态方法即可完成上下文数据的管理,通过这些方法设置和获取的值,都仅限于当前的协程,在协程结束时,对应的上下文也会自动跟随释放掉,无需手动管理,无需担忧内存泄漏的风险。
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Context;
/**
* @AutoController()
*/
class CoController{
public function get(){
//从当前协程上下文中取出 key 为 foo 的值,如不存在则返回 null 字符串
return Context::get('foo', 'null');
}
public function update(RequestInterface $request){
$foo = $request -> input('foo');
Context::set('foo', $foo);
return Context::get('foo');
}
}
第一步请求get方法 返回为空
第二步更新值 更新返回值为100
第三步 在获取看看是不是有影响–没有影响
处理方法二:协程上下文 + 魔术方法
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Context;
/**
* @AutoController()
*/
class CoController{
public function get(){
return $this->foo;
}
public function update(RequestInterface $request){
$foo = $request -> input('foo');
$this->foo = $foo;
return $this->foo;
}
public function __get($name){
//这个加class怕别的类有一样的, 这样确保一个类里面就一个
return Context::get(__CLASS__ . ":" . $name, 'null');
}
public function __set($name, $value){
return Context::set(__CLASS__. ":" . $name, $value);
}
}
//返回都正常,没有影响
通过Inject引入的类 – 出现的问题是会影响数据
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Context;
use Hyperf\Di\Annotation\Inject;
/**
* @AutoController()
*/
class CoController{
/**
* @Inject()
* @var \App\Foo
*/
private $foo;
public function get(){
return $this->foo->bar;
}
public function update(RequestInterface $request){
$foo = $request -> input('foo');
$this->foo->bar = $foo;
return $this->foo->bar;
}
}
<?php
namespace App;
Class Foo{
public $bar = 1;
}
//影响了数据—无论是不是静态属性,都会在全局共享,所以要把所有的值都存储到协程上下文中,协程上下文会在协程结束的时候释放掉,无需担忧内存泄漏的问题
那么问题, 如果是这种引入类的方法应该怎么解决呢
//引入这的代码不需要改变
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Context;
use Hyperf\Di\Annotation\Inject;
/**
* @AutoController()
*/
class CoController{
/**
* @Inject()
* @var \App\Foo
*/
private $foo;
public function get(){
return $this->foo->bar;
}
public function update(RequestInterface $request){
$foo = $request -> input('foo');
$this->foo->bar = $foo;
return $this->foo->bar;
}
}
//foo类改变就可以
<?php
namespace App;
use Hyperf\Utils\Context;
Class Foo{
public function __set($name, $value){
return Context::set(__CLASS__ . ":" .$name, $value);
}
public function __get($name){
return Context::get(__CLASS__ . ":" . $name);
}
}
效果