前几天在写公司代码的时候,使用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
的调用必然会段错误了。