]> granicus.if.org Git - php/commitdiff
Implement SplObjectStorage::getHash()
authorEtienne Kneuss <colder@php.net>
Thu, 29 Apr 2010 15:47:41 +0000 (15:47 +0000)
committerEtienne Kneuss <colder@php.net>
Thu, 29 Apr 2010 15:47:41 +0000 (15:47 +0000)
NEWS
ext/spl/spl_observer.c
ext/spl/tests/SplObjectStorage_getHash.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 308dfeb3e8581f0f36f244fb6021bc1a78a26582..46e0e3d69a52c5cc5bf2333e8aa618bf6c1ec41f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,7 @@
 - Added ReflectionZendExtension class. (Johannes)
 - Added command line option --rz to CLI. (Johannes)
 - Added closure $this support back. (Stas)
+- Added SplObjectStorage::getHash() hook. (Etienne)
 
 - default_charset if not specified is now UTF-8 instead of ISO-8859-1. (Rasmus)
 
index 7676d03c56b331e999278d42bbd2bd9c9a18e956..17ebe086af20b24bc7bad46b6eefda6ac0ebff5b 100755 (executable)
@@ -84,6 +84,7 @@ typedef struct _spl_SplObjectStorage { /* {{{ */
        long              index;
        HashPosition      pos;
        long              flags;
+       zend_function    *fptr_get_hash;
        HashTable        *debug_info;
 } spl_SplObjectStorage; /* }}} */
 
@@ -109,36 +110,96 @@ void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
        efree(object);
 } /* }}} */
 
+static char *spl_object_storage_get_hash(spl_SplObjectStorage *intern, zval *this,  zval *obj, int *hash_len_ptr TSRMLS_DC) {
+       if (intern->fptr_get_hash) {
+               zval *rv;
+               zend_call_method_with_1_params(&this, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, obj);
+               if (rv) {
+                       if (Z_TYPE_P(rv) == IS_STRING) {
+                               int hash_len = Z_STRLEN_P(rv);
+                               char *hash = emalloc((hash_len+1)*sizeof(char *));
+                               strncpy(hash, Z_STRVAL_P(rv), hash_len);
+                               hash[hash_len] = 0;
+
+                               zval_ptr_dtor(&rv);
+                               if (hash_len_ptr) {
+                                       *hash_len_ptr = hash_len;
+                               }
+                               return hash;
+                       } else {
+                               zend_throw_exception(spl_ce_RuntimeException, "Hash needs to be a string", 0 TSRMLS_CC);
+
+                               zval_ptr_dtor(&rv);
+                               return NULL;
+                       }
+               } else {
+                       return NULL;
+               }
+       } else {
+               int hash_len = sizeof(zend_object_value);
+
+#if HAVE_PACKED_OBJECT_VALUE
+               return (char*)&Z_OBJVAL_P(obj);
+#else
+               char *hash = emalloc((hash_len+1)*sizeof(char *));
+
+               zend_object_value zvalue;
+               memset(&zvalue, 0, sizeof(zend_object_value));
+               zvalue.handle = Z_OBJ_HANDLE_P(obj);
+               zvalue.handlers = Z_OBJ_HT_P(obj);
+
+               strncpy(hash, (char *)&zvalue, hash_len);
+               hash[hash_len] = 0;
+#endif
+
+               if (hash_len_ptr) {
+                       *hash_len_ptr = hash_len;
+               }
+               
+               return hash;
+       }
+}
+
+static void spl_object_storage_free_hash(spl_SplObjectStorage *intern, char *hash) {
+       if (intern->fptr_get_hash) {
+               efree(hash);
+       } else {
+#if HAVE_PACKED_OBJECT_VALUE
+               // Nothing to do
+#else
+               efree(hash);
+#endif
+       }
+}
+
 static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */
 {
        zval_ptr_dtor(&element->obj);
        zval_ptr_dtor(&element->inf);
 } /* }}} */
 
-spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
+spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, char *hash, int hash_len TSRMLS_DC) /* {{{ */
 {
        spl_SplObjectStorageElement *element;
-       zend_object_value *pzvalue;     
-#if HAVE_PACKED_OBJECT_VALUE
-       pzvalue = &Z_OBJVAL_P(obj);
-#else
-       zend_object_value zvalue;
-       memset(&zvalue, 0, sizeof(zend_object_value));
-       zvalue.handle = Z_OBJ_HANDLE_P(obj);
-       zvalue.handlers = Z_OBJ_HT_P(obj);
-       pzvalue = &zvalue;
-#endif
-       if (zend_hash_find(&intern->storage, (char*)pzvalue, sizeof(zend_object_value), (void**)&element) == SUCCESS) {
+       if (zend_hash_find(&intern->storage, hash, hash_len, (void**)&element) == SUCCESS) {
                return element;
        } else {
                return NULL;
        }
 } /* }}} */
 
-void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
+void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *this, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
 {
        spl_SplObjectStorageElement *pelement, element;
-       pelement = spl_object_storage_get(intern, obj TSRMLS_CC);
+       
+       int hash_len;
+       char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+       if (!hash) {
+               return;
+       }
+
+       pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+
        if (inf) {
                Z_ADDREF_P(inf);
        } else {
@@ -147,46 +208,34 @@ void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj, zval *in
        if (pelement) {
                zval_ptr_dtor(&pelement->inf);
                pelement->inf = inf;
+               spl_object_storage_free_hash(intern, hash);
                return;
        }
        Z_ADDREF_P(obj);
        element.obj = obj;
        element.inf = inf;
-#if HAVE_PACKED_OBJECT_VALUE
-       zend_hash_update(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);    
-#else
-       {
-               zend_object_value zvalue;
-               memset(&zvalue, 0, sizeof(zend_object_value));
-               zvalue.handle = Z_OBJ_HANDLE_P(obj);
-               zvalue.handlers = Z_OBJ_HT_P(obj);
-               zend_hash_update(&intern->storage, (char*)&zvalue, sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);
-       }
-#endif
+       zend_hash_update(&intern->storage, hash, hash_len, &element, sizeof(spl_SplObjectStorageElement), NULL);
+       spl_object_storage_free_hash(intern, hash);
 } /* }}} */
 
-void spl_object_storage_detach(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
+void spl_object_storage_detach(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */
 {
-#if HAVE_PACKED_OBJECT_VALUE
-       zend_hash_del(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
-#else
-       {
-               zend_object_value zvalue;
-               memset(&zvalue, 0, sizeof(zend_object_value));
-               zvalue.handle = Z_OBJ_HANDLE_P(obj);
-               zvalue.handlers = Z_OBJ_HT_P(obj);
-               zend_hash_del(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
+       int hash_len;
+       char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+       if (!hash) {
+               return;
        }
-#endif
+       zend_hash_del(&intern->storage, hash, hash_len);
+       spl_object_storage_free_hash(intern, hash);
 } /* }}}*/
 
-void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
+void spl_object_storage_addall(spl_SplObjectStorage *intern, zval *this, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
        HashPosition pos;
        spl_SplObjectStorageElement *element;
 
        zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
        while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
-               spl_object_storage_attach(intern, element->obj, element->inf TSRMLS_CC);
+               spl_object_storage_attach(intern, this, element->obj, element->inf TSRMLS_CC);
                zend_hash_move_forward_ex(&other->storage, &pos);
        }
 
@@ -214,7 +263,15 @@ static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type,
 
        if (orig) {
                spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC);
-               spl_object_storage_addall(intern, other TSRMLS_CC);
+               spl_object_storage_addall(intern, orig, other TSRMLS_CC);
+       }
+
+
+       if (class_type != spl_ce_SplObjectStorage) {
+               zend_hash_find(&class_type->function_table, "gethash",    sizeof("gethash"),    (void **) &intern->fptr_get_hash);
+               if (intern->fptr_get_hash->common.scope == spl_ce_SplObjectStorage) {
+                       intern->fptr_get_hash = NULL;
+               }
        }
 
        return retval;
@@ -320,19 +377,16 @@ static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type T
 }
 /* }}} */
 
-int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
+int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */
 {
-#if HAVE_PACKED_OBJECT_VALUE
-       return zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
-#else
-       {
-               zend_object_value zvalue;
-               memset(&zvalue, 0, sizeof(zend_object_value));
-               zvalue.handle = Z_OBJ_HANDLE_P(obj);
-               zvalue.handlers = Z_OBJ_HT_P(obj);
-               return zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
+       int hash_len;
+       char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
+       if (!hash) {
+               return 0;
        }
-#endif
+       int found = zend_hash_exists(&intern->storage, hash, hash_len);
+       spl_object_storage_free_hash(intern, hash);
+       return found;
 } /* }}} */
 
 /* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL)
@@ -346,7 +400,7 @@ SPL_METHOD(SplObjectStorage, attach)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
                return;
        }
-       spl_object_storage_attach(intern, obj, inf TSRMLS_CC);
+       spl_object_storage_attach(intern, getThis(), obj, inf TSRMLS_CC);
 } /* }}} */
 
 /* {{{ proto void SplObjectStorage::detach($obj)
@@ -359,12 +413,30 @@ SPL_METHOD(SplObjectStorage, detach)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                return;
        }
-       spl_object_storage_detach(intern, obj TSRMLS_CC);
+       spl_object_storage_detach(intern, getThis(), obj TSRMLS_CC);
 
        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
        intern->index = 0;
 } /* }}} */
 
+/* {{{ proto string SplObjectStorage::getHash($object)
+ Returns the hash of an object */
+SPL_METHOD(SplObjectStorage, getHash)
+{
+       zval *obj;
+       char *hash;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
+               return;
+       }
+
+       hash = emalloc(33);
+       php_spl_object_hash(obj, hash TSRMLS_CC);
+       
+       RETVAL_STRING(hash, 0);
+
+} /* }}} */
+
 /* {{{ proto mixed SplObjectStorage::offsetGet($object)
  Returns associated information for a stored object */
 SPL_METHOD(SplObjectStorage, offsetGet)
@@ -372,11 +444,21 @@ SPL_METHOD(SplObjectStorage, offsetGet)
        zval *obj;
        spl_SplObjectStorageElement *element;
        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
-       
+       char *hash;
+       int hash_len;
+
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                return;
        }
-       element = spl_object_storage_get(intern, obj TSRMLS_CC);
+
+       hash = spl_object_storage_get_hash(intern, getThis(), obj, &hash_len TSRMLS_CC);
+       if (!hash) {
+               return;
+       }
+
+       element = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
+       spl_object_storage_free_hash(intern, hash);
+
        if (!element) {
                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
        } else {
@@ -398,7 +480,7 @@ SPL_METHOD(SplObjectStorage, addAll)
 
        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
 
-       spl_object_storage_addall(intern, other TSRMLS_CC);
+       spl_object_storage_addall(intern, getThis(),  other TSRMLS_CC);
 
        RETURN_LONG(zend_hash_num_elements(&intern->storage));
 } /* }}} */
@@ -421,7 +503,7 @@ SPL_METHOD(SplObjectStorage, removeAll)
 
        zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
        while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
-               spl_object_storage_detach(intern, element->obj TSRMLS_CC);
+               spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC);
                zend_hash_move_forward_ex(&other->storage, &pos);
        }
 
@@ -441,7 +523,7 @@ SPL_METHOD(SplObjectStorage, contains)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                return;
        }
-       RETURN_BOOL(spl_object_storage_contains(intern, obj TSRMLS_CC));
+       RETURN_BOOL(spl_object_storage_contains(intern, getThis(), obj TSRMLS_CC));
 } /* }}} */
 
 /* {{{ proto int SplObjectStorage::count()
@@ -649,7 +731,7 @@ SPL_METHOD(SplObjectStorage, unserialize)
                                goto outexcept;
                        }
                }
-               spl_object_storage_attach(intern, pentry, pinf TSRMLS_CC);
+               spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC);
                zval_ptr_dtor(&pentry);
                zval_ptr_dtor(&pinf);
        }
@@ -704,6 +786,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
        ZEND_ARG_INFO(0, info)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO(arginfo_getHash, 0)
+       ZEND_ARG_INFO(0, object)
+ZEND_END_ARG_INFO();
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
        ZEND_ARG_INFO(0, object)
 ZEND_END_ARG_INFO()
@@ -724,6 +810,7 @@ static const zend_function_entry spl_funcs_SplObjectStorage[] = {
        SPL_ME(SplObjectStorage,  removeAll,   arginfo_Object,        0)
        SPL_ME(SplObjectStorage,  getInfo,     arginfo_splobject_void,0)
        SPL_ME(SplObjectStorage,  setInfo,     arginfo_setInfo,       0)
+       SPL_ME(SplObjectStorage,  getHash,     arginfo_getHash,       0)
        /* Countable */
        SPL_ME(SplObjectStorage,  count,       arginfo_splobject_void,0)
        /* Iterator */
@@ -829,7 +916,7 @@ SPL_METHOD(MultipleIterator, attachIterator)
                }
        }
 
-       spl_object_storage_attach(intern, iterator, info TSRMLS_CC);
+       spl_object_storage_attach(intern, getThis(), iterator, info TSRMLS_CC);
 }
 /* }}} */
 
diff --git a/ext/spl/tests/SplObjectStorage_getHash.phpt b/ext/spl/tests/SplObjectStorage_getHash.phpt
new file mode 100644 (file)
index 0000000..f309b3d
--- /dev/null
@@ -0,0 +1,60 @@
+--TEST--
+SplObjectStorage::getHash implementation
+--FILE--
+<?php
+$s = new SplObjectStorage();
+$o1 = new Stdclass;
+$o2 = new Stdclass;
+$s[$o1] = "some_value\n";
+echo $s->offsetGet($o1);
+
+class MySplObjectStorage extends SplObjectStorage {
+    public function getHash($obj) {
+        return 2;
+    }
+}
+
+try {
+    $s1 = new MySplObjectStorage;
+    $s1[$o1] = "foo";
+} catch(Exception $e) {
+    echo "caught\n";
+}
+
+class MySplObjectStorage2 extends SplObjectStorage {
+    public function getHash($obj) {
+        throw new Exception("foo");
+        return "asd";
+    }
+}
+
+try {
+    $s2 = new MySplObjectStorage2;
+    $s2[$o2] = "foo";
+} catch(Exception $e) {
+    echo "caught\n";
+}
+
+class MySplObjectStorage3 extends SplObjectStorage {
+    public function getHash($obj) {
+        return "asd";
+    }
+}
+
+$s3 = new MySplObjectStorage3;
+$s3[$o1] = $o1;
+var_dump($s3[$o1]);
+$s3[$o2] = $o2;
+
+var_dump($s3[$o1] === $s3[$o2]);
+
+?>
+===DONE===
+--EXPECT--
+some_value
+caught
+caught
+object(stdClass)#2 (0) {
+}
+bool(true)
+===DONE===