PHP7如何从常规列表中删除资源?

PHP7如何从常规列表中删除资源?,php,php-extension,php-7,php-internals,Php,Php Extension,Php 7,Php Internals,我正在将一个php扩展升级到PHP7,我想删除一个使用zend\u register\u resource在常规列表中注册的资源,然后我将使用zend\u list\u close关闭该资源。关闭函数如下所示: PHP_FUNCTION(myFunc_cleanAndExit) { zval* rsrc = NULL; ... int res = zend_parse_parameters(ZEND_NUM_ARGS() , "r", &rs

我正在将一个php扩展升级到PHP7,我想删除一个使用
zend\u register\u resource
在常规列表中注册的资源,然后我将使用
zend\u list\u close
关闭该资源。关闭函数如下所示:

    PHP_FUNCTION(myFunc_cleanAndExit)
    {
     zval* rsrc = NULL;
     ...
     int res = zend_parse_parameters(ZEND_NUM_ARGS() , "r", &rsrc );
     if (res == FAILURE)
     {
        //handle it
     }
     ...
     zend_fetch_resource(Z_RES_P(rsrc), ./other args/..)
     ...
     zend_list_close(Z_RES_P(rsrc));
     ...
     }
    myFunc_cleanAndExit($var-rsrc);
    myFunc_cleanAndExit($var-rsrc);
最初在PHP5中,
rsrc
是使用
zend\u hash\u index\u del(&EG(regular\u list),Z\u RESVAL\u p(rsrc))
删除的,因此如果调用两次此函数,
zend\u parse\u参数
返回
失败,因为资源已从常规列表中删除且不存在

在PHP7中,
zend_list_close
调用
zend_resource_dtor
(rsrc refcount是
2
(为什么是递增的?注册资源后是1)),并清除
rsrc
占用的所有内存。但是,有趣的是,当我们两次这样称呼它时:

    PHP_FUNCTION(myFunc_cleanAndExit)
    {
     zval* rsrc = NULL;
     ...
     int res = zend_parse_parameters(ZEND_NUM_ARGS() , "r", &rsrc );
     if (res == FAILURE)
     {
        //handle it
     }
     ...
     zend_fetch_resource(Z_RES_P(rsrc), ./other args/..)
     ...
     zend_list_close(Z_RES_P(rsrc));
     ...
     }
    myFunc_cleanAndExit($var-rsrc);
    myFunc_cleanAndExit($var-rsrc);
第二次zend_parse_参数不返回FAILURE(因为资源尚未从常规列表中删除),并且解析后
rsrc
的refcount增加到
3
,类型为-1,ptr为NULL(在第一次调用中在zend_resource_dtor中分配)。在PHP脚本中调用
get_resources()
时,我会得到带有id和类型
unknown
rsrc
,它在PHP5
rsrc
中变为
NULL
。以下是我的问题:

1-何时从常规列表中删除资源?(如果我使用
zend\u hash\u index\u del
手动将其从常规列表中删除,它将在zend\u alloc中中断)

2-关闭一次后,是否可以使用类型为
未知的
激活资源?不会耗尽记忆吗?如果不是,我应该如何将其设置为空

3-当我注册资源并检查其refcount时,它是1,但当我调用closing函数时,在
zend\u parse\u参数之后,refcount会增加,为什么

谢谢

PHP脚本示例:

    <?php
    $var_rsrc = myFunc_startUp();
    var_dump($var_rsrc); // resource(2) of type 'MyFunc'
    myFunc_cleanAndExit($var_rsrc);
    var_dump($var_rsrc); // resource(2) of type 'UNKOWN' (originally this was  NULL)
    myFunc_cleanAndExit($var_rsrc);
    var_dump($var_rsrc); // resource(2) of type 'UNKOWN'

简单的回答是,资源在请求关闭时被删除,特别是在
zend\u hash\u优雅\u reverse\u destroy
中。您还应该检查
zend_fetch_resource
的返回值,因为它将为已破坏的资源返回NULL(并发出警告)

我认为您所描述的一切都是正常的,包括
zend_parse_参数
成功解析以前被破坏的资源。下面的程序显示了完全相同的行为:

<?php
$r = popen('ls', 'r');
echo fgets($r);
pclose($r);
var_dump(get_resources());
pclose($r);

谢谢@adsr,在PHP5 zend_parse_中,参数返回失败,因为该参数实际上不存在并且已从列表中删除,为什么我们不能在PHP7中有相同的行为?@Genjutsu感谢接受我的回答。我有点怀疑这种改变是故意的。这更有可能是堆栈与堆分配ZVAL的副作用。作为一个边缘案例,您可以争辩说,有人可能想要重新实例化他们以前破坏的资源,在这种情况下,zpp成功是可取的。将其与PHP5的背部兼容性进行权衡,这是一个难题。