在 PHP 中获取对象的实例 ID

2022-08-30 15:08:06

我不久前在StackOverflow上了解到,我们可以获取任何资源的“实例ID”,例如:

var_dump(intval(curl_init()));  // int(2)
var_dump(intval(finfo_open())); // int(3)
var_dump(intval(curl_init()));  // int(4)
var_dump(intval(finfo_open())); // int(5)
var_dump(intval(curl_init()));  // int(6)

我需要类似的东西,但应用于类:

class foo {
    public function __construct() {
        ob_start();
        var_dump($this); // object(foo)#INSTANCE_ID (0) { }
        echo preg_replace('~.+#(\d+).+~s', '$1', ob_get_clean());
    }
}

$foo = new foo();  // 1
$foo2 = new foo(); // 2

上述方法有效,但我希望有一个更快的解决方案,或者至少是一个不涉及输出缓冲区的解决方案。请注意,这不一定在构造函数内使用,甚至在类本身内部使用!

spl_object_hash()不是我想要的,因为这两个对象产生相同的哈希值

这个问题以前包含一个不正确的输出示例;确保两个对象同时存在会产生明显不同的哈希值:spl_object_hash

var_dump(spl_object_hash($foo));  // 0000000079e5f3b60000000042b31773
var_dump(spl_object_hash($foo2)); // 0000000079e5f3b50000000042b31773

转换为 int 之类的资源似乎不适用于对象:

通知:类 foo 的对象无法转换为 int。

有没有一种快速的方法可以在不使用对象属性的情况下获取相同的输出

此外,我通过反复试验发现debug_zval_dump()也输出对象实例,不幸的是,它也需要输出缓冲,因为它不返回结果。var_dump()


答案 1

spl_object_hash()可以在这里帮助你。它

返回对象的唯一标识符

对于给定的实例,这始终是相同的。

操作注释后编辑:

您可以使用静态类属性实现此类行为,例如:

class MyClass 
{
    private static $_initialized = false;

    public function __construct()
    {
        if (!self::$_initialized) {
            self::$_initialized = true;
            // your run-only-once code 
        }
    }
}

但实际上,这与你原来的问题无关。


答案 2

好吧,是的,带有扩展名。

请注意,用于同时被销毁的对象的句柄可以重复使用。

构建方式phpize && ./configure && make && make install

testext.h

#ifndef PHP_EXTTEST_H
# define PHP_EXTTEST_H
# ifdef HAVE_CONFIG_H
#  include<config.h>
# endif
# include <php.h>
extern zend_module_entry testext_module_entry;
#define phpext_testext_ptr &testext_module_entry
#endif

testext.c

#include "testext.h"

PHP_FUNCTION(get_object_id)
{
    zval *obj;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj)
            == FAILURE) {
        return;
    }

    RETURN_LONG(Z_OBJ_HANDLE_P(obj));
}

static zend_function_entry ext_functions[] = {
    PHP_FE(get_object_id, NULL)
    {NULL, NULL, NULL, 0, 0}
};

zend_module_entry testext_module_entry = {
    STANDARD_MODULE_HEADER,
    "testext",
    ext_functions, /* Functions */
    NULL, /* MINIT */
    NULL, /* MSHUTDOWN */
    NULL, /* RINIT */
    NULL, /* RSHUTDOWN */
    NULL, /* MINFO */
    NO_VERSION_YET,
    STANDARD_MODULE_PROPERTIES
};

ZEND_GET_MODULE(testext)

配置.m4

PHP_ARG_ENABLE(testext,
  [Whether to enable the "testext" extension],
  [  enable-testext         Enable "testext" extension support])

if test $PHP_EXTTEST != "no"; then
  PHP_SUBST(EXTTEST_SHARED_LIBADD)
  PHP_NEW_EXTENSION(testext, testext.c, $ext_shared)
fi

测试脚本

<?php
$a = new stdclass();
$b = new stdclass();
var_dump(get_object_id($a));
var_dump(get_object_id($b));

输出

int(1)
int(2)

推荐