前几天在写公司代码的时候,使用Hyperf写了大概这么一段代码:
1 | class IndexController |
然后,在执行$this->request->getHeaders();这一行报错了,说是某某某接口没有实现。但是,如果我把这一行代码直接放在创建协程的外面,也就是这么写:
1 | class IndexController |
就不会报错了。
具体要怎么解决这个问题不是我们这篇文章讨论的重点。这个问题一开始让我产生了一个疑问,以为不能在创建的子协程里面使用$this。
然后,我写了这么一段代码来进行测试:
1 |
|
输出结果如下:
1 | string(4) "foo1" |
发现,在子协程里面使用$this完全没有问题。
然后,回想到了编译原理的面向对象的语义特征里面作用域角度(我在我的这篇博客有讲解),我看了看Swoole的实现,果然发现有一部分代码是把$this复制到了子协程栈里面,实际上对应的就是EX(This):
1 | call = zend_vm_stack_push_call_frame( |
如果fci_cache.object改成传nullptr的话,执行我们的脚本,就会报这个错误:
1 | string(4) "foo1" |
说明,我们获取$this的时候出了问题。
实际上,PHP对$this->test1()的生成的opcode是INIT_METHOD_CALL,对应的handler是ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER。我们一定会在这个handler里面看到从作用域里面去获取$this的过程。
如果我们传递的fci_cache.object是nullptr,意味着子协程作用域的EX(This)是nullptr,那么EX(This)对foo1的调用必然会段错误了。