public
Last active

get_objects_count function for RFC

  • Download Gist
get_object_stats
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
--- 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 */

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

Better now, skipping destroyed objects

Remember to use zend_parse_parameters_none()

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

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

+parse_parameters_none()

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

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?

Some more suggestions:

get_objects_count()

get_instances_count()

get_object_store_count()

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.

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... :)

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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.