From e6ee260b259cf2ba9ecdcca6b7e7648d6350c457 Mon Sep 17 00:00:00 2001 From: Etienne Kneuss Date: Thu, 29 Apr 2010 15:47:41 +0000 Subject: [PATCH] Implement SplObjectStorage::getHash() --- NEWS | 1 + ext/spl/spl_observer.c | 205 ++++++++++++++------ ext/spl/tests/SplObjectStorage_getHash.phpt | 60 ++++++ 3 files changed, 207 insertions(+), 59 deletions(-) create mode 100644 ext/spl/tests/SplObjectStorage_getHash.phpt diff --git a/NEWS b/NEWS index 308dfeb3e8..46e0e3d69a 100644 --- 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) diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c index 7676d03c56..17ebe086af 100755 --- a/ext/spl/spl_observer.c +++ b/ext/spl/spl_observer.c @@ -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 index 0000000000..f309b3d84f --- /dev/null +++ b/ext/spl/tests/SplObjectStorage_getHash.phpt @@ -0,0 +1,60 @@ +--TEST-- +SplObjectStorage::getHash implementation +--FILE-- +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=== -- 2.40.0