PHP 7 如何从常规列表中删除资源?
How does PHP 7 remove the resources from the regular list?
我正在将 php 扩展升级到 php 7,我想删除使用 zend_register_resource
在常规列表中注册的资源,稍后我将关闭资源使用 zend_list_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));
...
}
原来在PHP5中,rsrc
是用zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( rsrc))
去掉的,所以如果这个函数被调用两次,zend_parse_parameter
returnsFAILURE
,因为该资源已从常规列表中删除并且不存在。
在PHP7中,zend_list_close
调用zend_resource_dtor
(rsrc refcount是2
(为什么是递增的?注册资源后它是1))并清除任何rsrc
的记忆。但是,当我们像这样调用它两次时,乐趣就来了:
myFunc_cleanAndExit($var-rsrc);
myFunc_cleanAndExit($var-rsrc);
第二次zend_parse_parameter没有return失败(因为资源还没有从常规列表中删除),rsrc
的引用计数增加到3
解析后类型为-1,ptr为NULL(第一次调用时在zend_resource_dtor中赋值)。当我在 PHP 脚本中调用 get_resources()
时,我得到 rsrc
及其 ID 和类型 UNKOWN
,在 PHP5 rsrc
中变为NULL
。这是我的问题:
1- 什么时候从常规列表中删除资源? (如果我使用 zend_hash_index_del
从常规列表中手动删除它,它会在 zend_alloc 中中断)
2- 在关闭一次后让类型为 UNKOWN
的资源处于活动状态是否可以?不吃掉内存?如果不是,我应该怎么做才能让它为 NULL?
3- 当我注册资源并检查它的引用计数时,它是 1,但是当我调用关闭函数时,在 zend_parse_parameter
之后引用计数增加了,为什么?
谢谢
示例 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_hash_graceful_reverse_destroy
中。您还应该检查 zend_fetch_resource
的 return 值,因为它将 return NULL(并发出警告)用于已破坏的资源。
我认为您所描述的一切都是正常的,包括 zend_parse_parameters
成功解析了先前被破坏的资源。下面的程序表现出完全相同的行为:
<?php
$r = popen('ls', 'r');
echo fgets($r);
pclose($r);
var_dump(get_resources());
pclose($r);
您的资源的引用计数是 2,因为 SEND_VAR
操作码(即,将参数传递给函数)会将其 ZVAL_COPY
到 arglist,这会增加引用计数。 (稍后在 zend_vm_stack_free_args
中取消引用)
关于内存使用,我不担心资源占用内存。我们已经知道它不会泄漏,因为它会在 RSHUTDOWN
被清理干净。即使您手动从散列中删除该项目,我也不认为保证会立即释放底层内存。
我正在将 php 扩展升级到 php 7,我想删除使用 zend_register_resource
在常规列表中注册的资源,稍后我将关闭资源使用 zend_list_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));
...
}
原来在PHP5中,rsrc
是用zend_hash_index_del( &EG( regular_list ), Z_RESVAL_P( rsrc))
去掉的,所以如果这个函数被调用两次,zend_parse_parameter
returnsFAILURE
,因为该资源已从常规列表中删除并且不存在。
在PHP7中,zend_list_close
调用zend_resource_dtor
(rsrc refcount是2
(为什么是递增的?注册资源后它是1))并清除任何rsrc
的记忆。但是,当我们像这样调用它两次时,乐趣就来了:
myFunc_cleanAndExit($var-rsrc);
myFunc_cleanAndExit($var-rsrc);
第二次zend_parse_parameter没有return失败(因为资源还没有从常规列表中删除),rsrc
的引用计数增加到3
解析后类型为-1,ptr为NULL(第一次调用时在zend_resource_dtor中赋值)。当我在 PHP 脚本中调用 get_resources()
时,我得到 rsrc
及其 ID 和类型 UNKOWN
,在 PHP5 rsrc
中变为NULL
。这是我的问题:
1- 什么时候从常规列表中删除资源? (如果我使用 zend_hash_index_del
从常规列表中手动删除它,它会在 zend_alloc 中中断)
2- 在关闭一次后让类型为 UNKOWN
的资源处于活动状态是否可以?不吃掉内存?如果不是,我应该怎么做才能让它为 NULL?
3- 当我注册资源并检查它的引用计数时,它是 1,但是当我调用关闭函数时,在 zend_parse_parameter
之后引用计数增加了,为什么?
谢谢
示例 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_hash_graceful_reverse_destroy
中。您还应该检查 zend_fetch_resource
的 return 值,因为它将 return NULL(并发出警告)用于已破坏的资源。
我认为您所描述的一切都是正常的,包括 zend_parse_parameters
成功解析了先前被破坏的资源。下面的程序表现出完全相同的行为:
<?php
$r = popen('ls', 'r');
echo fgets($r);
pclose($r);
var_dump(get_resources());
pclose($r);
您的资源的引用计数是 2,因为 SEND_VAR
操作码(即,将参数传递给函数)会将其 ZVAL_COPY
到 arglist,这会增加引用计数。 (稍后在 zend_vm_stack_free_args
中取消引用)
关于内存使用,我不担心资源占用内存。我们已经知道它不会泄漏,因为它会在 RSHUTDOWN
被清理干净。即使您手动从散列中删除该项目,我也不认为保证会立即释放底层内存。