this 是 nullptr_为什么类方法中创建Swoole协程之后可以使用$this

前几天在写公司代码的时候,使用Hyperf写了大概这么一段代码:

class IndexController
{
    public function test1()
    {
        Coroutine::create(function () {
            $this->request->getHeaders();
        });
    }
}

然后,在执行$this->request->getHeaders();这一行报错了,说是某某某接口没有实现。但是,如果我把这一行代码直接放在创建协程的外面,也就是这么写:

class IndexController
{
    public function test1()
    {
        $this->request->getHeaders();
    }
}

就不会报错了。

具体要怎么解决这个问题不是我们这篇文章讨论的重点。这个问题一开始让我产生了一个疑问,以为不能在创建的子协程里面使用$this

然后,我写了这么一段代码来进行测试:

<?php

class Foo
{
    public function test1()
    {
        var_dump('foo1');
        go(function () {
            $this->test2();
        });
    }

    public function test2()
    {
        var_dump('foo2');
    }
}

$foo = new Foo;
$foo->test1();

输出结果如下:

string(4) "foo1"
string(4) "foo2"

发现,在子协程里面使用$this完全没有问题。

然后,回想到了编译原理的面向对象的语义特征里面作用域角度(我在我的这篇博客有讲解),我看了看Swoole的实现,果然发现有一部分代码是把$this复制到了子协程栈里面,实际上对应的就是EX(This)

call = zend_vm_stack_push_call_frame(
            ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED, func, argc, fci_cache.called_scope, fci_cache.object);

如果fci_cache.object改成传nullptr的话,执行我们的脚本,就会报这个错误:

string(4) "foo1"
[1]    60865 segmentation fault  php test.php

说明,我们获取$this的时候出了问题。

实际上,PHP$this->test1()的生成的opcodeINIT_METHOD_CALL,对应的handlerZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER。我们一定会在这个handler里面看到从作用域里面去获取$this的过程。

如果我们传递的fci_cache.objectnullptr,意味着子协程作用域的EX(This)nullptr,那么EX(This)foo1的调用必然会段错误了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值