使用内存引用比较PHP数组

Kir*_*met 6 php arrays php-internals

是否有可能看到两个数组变量是否指向相同的内存位置?(它们是相同的阵列)

Rah*_*hly 15

实际上,这可以做到.通过php扩展.

文件:config.m4

PHP_ARG_ENABLE(test, whether to enable test Extension support, [ --enable-test   Enable test ext support])

if test "$PHP_TEST" = "yes"; then
  AC_DEFINE(HAVE_TEST, 1, [Enable TEST Extension])
  PHP_NEW_EXTENSION(test, test.c, $ext_shared)
fi

文件:php_test.h

#ifndef PHP_TEST_H
#define PHP_TEST_H 1

#define PHP_TEST_EXT_VERSION "1.0"
#define PHP_TEST_EXT_EXTNAME "test"

PHP_FUNCTION(getaddress4);
PHP_FUNCTION(getaddress);

extern zend_module_entry test_module_entry;
#define phpext_test_ptr &test_module_entry

#endif

文件:test.c

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_test.h"

ZEND_BEGIN_ARG_INFO_EX(func_args, 1, 0, 0)
ZEND_END_ARG_INFO()

static function_entry test_functions[] = {
    PHP_FE(getaddress4, func_args)
    PHP_FE(getaddress, func_args)
    {NULL, NULL, NULL}
};

zend_module_entry test_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_TEST_EXT_EXTNAME,
    test_functions,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
#if ZEND_MODULE_API_NO >= 20010901
    PHP_TEST_EXT_VERSION,
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_TEST
ZEND_GET_MODULE(test)
#endif

PHP_FUNCTION(getaddress4)
{
    zval *var1;
    zval *var2;
    zval *var3;
    zval *var4;
    char r[500];
    if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "aaaa", &var1, &var2, &var3, &var4) == FAILURE ) {
      RETURN_NULL();
    }
    sprintf(r, "\n%p - %p - %p - %p\n%p - %p - %p - %p", var1, var2, var3, var4, Z_ARRVAL_P(var1), Z_ARRVAL_P(var2), Z_ARRVAL_P(var3), Z_ARRVAL_P(var4) );
    RETURN_STRING(r, 1);
}

PHP_FUNCTION(getaddress)
{
    zval *var;
    char r[100];
    if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &var) == FAILURE ) {
      RETURN_NULL();
    }
    sprintf(r, "%p", Z_ARRVAL_P(var));
    RETURN_STRING(r, 1);
}

然后你所要做的就是phpize它,配置它,然后制作它.在php.ini文件中添加"extension =/path/to/so/file/modules/test.so".最后,重启Web服务器,以防万一.

<?php
  $x = array("123"=>"123");
  $w = $x;
  $y = $x;
  $z = &$x;
  var_dump(getaddress4($w,$x,$y,$z));
  var_dump(getaddress($w));
  var_dump(getaddress($x));
  var_dump(getaddress($y));
  var_dump(getaddress($z));
?>

返回(至少对我来说,你的内存地址可能会有所不同)

string '
0x9efeb0 - 0x9effe0 - 0x9ef8c0 - 0x9efeb0
0x9efee0 - 0x9f0010 - 0x9ed790 - 0x9efee0' (length=84)

string '0x9efee0' (length=8)

string '0x9f0010' (length=8)

string '0x9ed790' (length=8)

string '0x9efee0' (length=8)

感谢Artefacto指出这一点,但是我的原始代码是按值传递数组,因此重新创建了包含引用的数组,并为您提供了错误的内存值.我已经改变了代码以强制所有参数通过引用传递.这将允许引用,数组和对象在php引擎中不受干扰地传递.$ w/$ z是相同的,但是$ w/$ x/$ y不是.旧代码实际上显示了引用破坏以及当所有变量传递给多个调用同一函数时内存地址将改变或匹配的事实.这是因为PHP在进行多次调用时会重用相同的内存.比较原始函数的结果将是无用的.新代码应该解决这个问题.

仅供参考 - 我使用的是php 5.3.2.

  • @Jeremy如果你做了`$ x = array(); $ z = $ x;`,然后`$ z`和`$ x`确实指向相同的`zval*`,直到强制分离(写时复制机制).你的例子略有不同 - 当你执行`$ w = $ x;`时,`$ w`和`$ x`指向相同的`zval*`(refcount = 2,is_ref = 0).但当你执行`$ z =&$ x;`时,你强迫分离,因为`$ z`和`$ x`是引用而`$ w`不是,而zval不能有两个不同的值. is_ref`字段.因此复制了第一个zval($ w/$ x)并且其refcount递减.新副本($ z/$ x; after)将refcount设置为2,并且is_ref = 1. (2认同)

net*_*der 9

你的问题实际上有点误导."指向相同的内存位置"和"是相同的数组"(这对我来说意味着是一个引用,至少在PHP中)是不一样的东西.

内存位置指的是指针.指针不适用于PHP.引用不是指针.

无论如何,如果你想检查是否$b实际上是一个参考$a,这是你可以得到一个真正的答案:

function is_ref_to(&$a, &$b) {
    if (is_object($a) && is_object($b)) {
        return ($a === $b);
    }

    $temp_a = $a;
    $temp_b = $b;

    $key = uniqid('is_ref_to', true);
    $b = $key;

    if ($a === $key) $return = true;
    else $return = false;

    $a = $temp_a;
    $b = $temp_b;
    return $return; 
}

$a = array('foo');
$b = array('foo');
$c = &$a;
$d = $a;

var_dump(is_ref_to($a, $b)); // false
var_dump(is_ref_to($b, $c)); // false
var_dump(is_ref_to($a, $c)); // true
var_dump(is_ref_to($a, $d)); // false
var_dump($a); // is still array('foo')
Run Code Online (Sandbox Code Playgroud)

  • 是..基本上问题应该是:`是否有可能看到两个数组变量是否指向相同的内存位置?`没有`(它们是相同的数组)-remark`.然后答案是; `no`. (2认同)
  • @stereofrog:`你也可以把php5对象(这是指针)`,不,它们不是指针. (2认同)

Wou*_*elo 8

PHP中的引用是一种通过不同名称访问相同变量内容的方法.它们不像C指针; 例如,您不能使用它们执行指针运算,它们不是实际的内存地址,依此类推.

结论:不,你不能

来自:http://www.php.net/manual/en/language.references.whatare.php