Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Instance ID of an Object in PHP

I've learn a while ago on StackOverflow that we can get the "instance ID" of any resource, for instance:

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) 

I need something similar but applied to classes:

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 

The above works but I was hoping for a faster solution or, at least, one that didn't involve output buffers. Please note that this won't necessarily be used within the constructor or even inside the class itself!

spl_object_hash() is not what I'm looking for because the two objects produce identical hashes

The question previously contained an incorrect example of spl_object_hash output; ensuring that both objects exist at the same time produces hashes which are subtly different:

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

Casting to int like resources doesn't seem to work for objects:

Notice: Object of class foo could not be converted to int.

Is there a quick way to grab the same output without using object properties?

Besides var_dump(), I've discovered by trial and error that debug_zval_dump() also outputs the object instance, unfortunately it also needs output buffering since it doesn't return the result.

like image 209
Alix Axel Avatar asked May 20 '10 09:05

Alix Axel


2 Answers

spl_object_hash() could help you out here. It

returns a unique identifier for the object

which is always the same for a given instance.

EDIT after OP comment:

You could implement such a behavior using a static class property, e.g:

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

But actually this has nothing to with your original question.

like image 141
Stefan Gehrig Avatar answered Sep 18 '22 14:09

Stefan Gehrig


Well, yes, with an extension.

Note that the handles used for objects that were, in the meantime, destroyed, can be reused.

Build with 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) 

config.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 

Test script

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

Output

 int(1) int(2) 
like image 29
Artefacto Avatar answered Sep 18 '22 14:09

Artefacto