Skip to content

Instantly share code, notes, and snippets.

@krakjoe
Last active December 15, 2015 14:39
Show Gist options
  • Save krakjoe/5275773 to your computer and use it in GitHub Desktop.
Save krakjoe/5275773 to your computer and use it in GitHub Desktop.
get_objects_count function for RFC
--- php-virgin/Zend/zend_builtin_functions.c 2013-04-04 16:44:42.930473062 +0100
+++ php-nts/Zend/zend_builtin_functions.c 2013-04-10 08:39:54.716250434 +0100
@@ -64,6 +64,7 @@
static ZEND_FUNCTION(is_subclass_of);
static ZEND_FUNCTION(is_a);
static ZEND_FUNCTION(get_class_vars);
+static ZEND_FUNCTION(get_objects_count);
static ZEND_FUNCTION(get_object_vars);
static ZEND_FUNCTION(get_class_methods);
static ZEND_FUNCTION(trigger_error);
@@ -154,6 +155,10 @@
ZEND_ARG_INFO(0, obj)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_get_objects_count, 0, 0, 0)
+ ZEND_ARG_INFO(0, criteria)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_class_methods, 0, 0, 1)
ZEND_ARG_INFO(0, class)
ZEND_END_ARG_INFO()
@@ -277,6 +282,7 @@
ZEND_FE(is_a, arginfo_is_subclass_of)
ZEND_FE(get_class_vars, arginfo_get_class_vars)
ZEND_FE(get_object_vars, arginfo_get_object_vars)
+ ZEND_FE(get_objects_count, arginfo_get_objects_count)
ZEND_FE(get_class_methods, arginfo_get_class_methods)
ZEND_FE(trigger_error, arginfo_trigger_error)
ZEND_FALIAS(user_error, trigger_error, arginfo_trigger_error)
@@ -976,6 +982,153 @@
}
/* }}} */
+/* {{{ _zend_hash_index_search */
+static inline zend_ulong _zend_hash_index_search(HashTable* ht, zval *pzval, zend_ulong *index TSRMLS_DC) {
+ HashPosition position;
+ zval **search = NULL;
+
+ /* nothing to do */
+ if (Z_TYPE_P(pzval) == IS_NULL)
+ return FAILURE;
+
+ for (zend_hash_internal_pointer_reset_ex(ht, &position);
+ zend_hash_get_current_data_ex(ht, (void**) &search, &position) == SUCCESS;
+ zend_hash_move_forward_ex(ht, &position)) {
+
+ switch (Z_TYPE_P(pzval)) {
+
+ /* perform string comparison */
+ case IS_STRING: {
+ if (strncmp(Z_STRVAL_PP(search), Z_STRVAL_P(pzval), Z_STRLEN_P(pzval)) == SUCCESS) {
+ char *ks;
+ zend_uint kl;
+
+ if (zend_hash_get_current_key_ex(ht, &ks, &kl, index, 0, &position) == HASH_KEY_IS_LONG) {
+ return SUCCESS;
+ }
+ }
+ } break;
+ }
+ }
+
+ return FAILURE;
+} /* }}} */
+
+/* {{{ proto mixed get_objects_count([mixed criteria])
+ where no criteria is provided will return the number of all objects in the object store as an associative array of class => count
+ where a class name is provided, returns the number of objects of the specified class in the object store
+ where an object is provided, returns the number of objects of the specified objects class in the object store
+ where an array is provided, the array is treated as an inclusive indexed array of class names, returns an associative array of class => count */
+ZEND_FUNCTION(get_objects_count)
+{
+ zend_class_entry *pce = NULL;
+ zval *pzarg = NULL;
+ HashTable *class_list = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &pzarg) != SUCCESS)
+ return;
+
+ if (pzarg) {
+ switch (Z_TYPE_P(pzarg)) {
+ /* take a string argument representing a class name */
+ case IS_STRING: {
+ zend_class_entry **ppce;
+ if (zend_lookup_class(Z_STRVAL_P(pzarg), Z_STRLEN_P(pzarg), &ppce TSRMLS_CC) != SUCCESS) {
+ zend_error(
+ E_WARNING, "%s() could not find the class requested (%s)",
+ get_active_function_name(TSRMLS_C), Z_STRVAL_P(pzarg));
+ return;
+ }
+ pce = *ppce;
+ } break;
+
+ /* use the class of this object directly */
+ case IS_OBJECT: {
+ pce = Z_OBJCE_P(pzarg);
+ } break;
+
+ /* use an array as indexed class names */
+ case IS_ARRAY: {
+ class_list = Z_ARRVAL_P(pzarg);
+ } break;
+
+ /* woops ! */
+ default: {
+ zend_error(E_WARNING, "%s() expects a string or object argument", get_active_function_name(TSRMLS_C));
+ return;
+ }
+ }
+
+ if (!class_list) {
+ ZVAL_LONG(return_value, 0);
+ /* skip to entry */
+ goto enter;
+ }
+ }
+
+ /* default initialization of return value/type */
+ array_init(return_value);
+
+ /* operation entry point */
+enter:
+ {
+ zend_uint zhandle = 1;
+
+ /* loop over all of objects in store */
+ while (zhandle < EG(objects_store).top) {
+
+ /* check the object has not been destroyed */
+ if (!EG(objects_store).object_buckets[zhandle].destructor_called) {
+
+ zend_object *zobject = (zend_object*) (EG(objects_store).object_buckets[zhandle].bucket.obj.object);
+
+ if (zobject && zobject->ce) {
+
+ /* match with specific entry */
+ if (pce) {
+ if (pce == zobject->ce) {
+ ++Z_LVAL_P(return_value);
+ }
+ } else {
+ /* match with strings and arrays */
+ zval *zcount;
+ zval **zcounted;
+
+ size_t zlength = strlen(zobject->ce->name);
+
+ if (class_list) {
+ zend_ulong exists;
+ zval zclass;
+
+ /* make temp zval for searching */
+ ZVAL_STRINGL(&zclass, zobject->ce->name, zlength, 0);
+
+ /* attempt to find this classes name in the parameter array */
+ if (_zend_hash_index_search(class_list, &zclass, &exists TSRMLS_CC) != SUCCESS) {
+ goto omit;
+ }
+ }
+
+ /* calculate how to ammed return array */
+ if (zend_hash_find(Z_ARRVAL_P(return_value), zobject->ce->name, zlength+1, (void**)&zcounted) == SUCCESS) {
+ MAKE_STD_ZVAL(zcount);
+ ZVAL_LONG(zcount, Z_LVAL_PP(zcounted)+1);
+ } else {
+ MAKE_STD_ZVAL(zcount);
+ ZVAL_LONG(zcount, 1);
+ }
+
+ /* ammend return array */
+ zend_hash_update(
+ Z_ARRVAL_P(return_value), zobject->ce->name, zlength+1, (void**)&zcount, sizeof(zval), NULL);
+ }
+ }
+ }
+omit:
+ zhandle++;
+ }
+ }
+} /* }}} */
/* {{{ proto array get_object_vars(object obj)
Returns an array of object properties */
@Trainmaster
Copy link

So far, nobody else commented on my idea. I'm gonna wait until Friday and see if that is still the case. If so, I will write the RFC on saturday.

Concerning the name: I would definitely go with the plural form. The reason for that is, that all other functions with "class" in it, like class_alias(), class_exists(), get_class(), get_class_vars() ... refer to a single class.

But once again: a class is rather more a construct/definition than an object/instance. See wikipedia for example, http://en.wikipedia.org/wiki/Class_%28computer_programming%29

It says:

"a class is a construct that is used to create instances of itself – referred to as class instances, class objects, instance objects or simply objects".

That's why I think "objects" or "instances" should be in the name.

Looking at the docs, both objects and instances are being used, http://www.php.net/manual/en/language.oop5.basic.php.

Right now I think that instances is the most exact one.

I will continue with research... :)

@krakjoe
Copy link
Author

krakjoe commented Apr 6, 2013

get_instance_counts ? would you like the name revised before you write an rfc ?

btw, you can get hold of me quicker on irc, krakjoe pecl.dev efnet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment