Skip to content

Instantly share code, notes, and snippets.

@krakjoe
Last active December 15, 2015 14:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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 */
@krakjoe
Copy link
Author

krakjoe commented Mar 30, 2013

This is a bit too simplistic ... destroyed objects will cause segfaults right now ...

@krakjoe
Copy link
Author

krakjoe commented Mar 30, 2013

Better now, skipping destroyed objects

@KalleZ
Copy link

KalleZ commented Mar 30, 2013

Remember to use zend_parse_parameters_none()

@KalleZ
Copy link

KalleZ commented Mar 30, 2013

Thinking about it, it might be better suited inside zend_builtin_functions.c

@krakjoe
Copy link
Author

krakjoe commented Mar 30, 2013

Yeah I'm not really sure where it should go ...

+parse_parameters_none()

... also, not sure about name ...

@Trainmaster
Copy link

Thank you for taking the time to create an implementation.

Regarding the name I think it should fit into the names of the class/object functions. http://www.php.net/manual/en/ref.classobj.php

Since there is already get_object_vars(), one might think, that get_object_stats() returns stats of a concrete object. Furthermore, "stats" sounds a bit too general.

Therefore, I (=Frank) suggested get_instantiated_classes(). Is it too verbose?

@Trainmaster
Copy link

Some more suggestions:

get_objects_count()

get_instances_count()

get_object_store_count()

@krakjoe
Copy link
Author

krakjoe commented Mar 30, 2013

get_class_counts() seems to be most inline with that, and the most exact ... the user doesn't know about the object store in general, instances/objects is not very exact (could purtain to variable names) ... but then it's purpose is not very obvious from get_class_counts() ...

We'll see what others think, if anything ... I've not really the time to create an RFC, or have the conversations that go with it, but happy to work on the patch for you if it requires it, so go ahead and create an RFC if you are serious about it being introduced, be sure you read a few accepted RFC's and include as much information as you can think of about why it is useful to add YAF :)

It's name could be something you include in the said RFC.

@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