1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
<?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) 静态方法即可完成上下文数据的管理,通过这些方法设置和获取的值,都仅限于当前的协程,在协程结束时,对应的上下文也会自动跟随释放掉,无需手动管理,无需担忧内存泄漏的风险。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
<?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

第三步 在获取看看是不是有影响–没有影响

处理方法二:协程上下文 + 魔术方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
<?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引入的类 – 出现的问题是会影响数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
<?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; } |
//影响了数据—无论是不是静态属性,都会在全局共享,所以要把所有的值都存储到协程上下文中,协程上下文会在协程结束的时候释放掉,无需担忧内存泄漏的问题

那么问题, 如果是这种引入类的方法应该怎么解决呢
//引入这的代码不需要改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
<?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); } } |
效果

来源:https://blog.csdn.net/a603423130/article/details/118053787
「三年博客,如果觉得我的文章对您有用,请帮助本站成长」
共有 0 - hyperf 协程数据混淆的思考和分析