- static PyObject * convert_zval_to_pyobject(zval **val)
- {
- PyObject *ret;
- if (val == NULL) {
- return NULL;
- }
- switch (Z_TYPE_PP(val)) {
- case IS_BOOL:
- ret = Py_BuildValue("i", Z_LVAL_PP(val) ? 1 : 0);
- break;
- case IS_LONG:
- ret = Py_BuildValue("l", Z_LVAL_PP(val));
- break;
- case IS_DOUBLE:
- ret = Py_BuildValue("d", Z_DVAL_PP(val));
- break;
- case IS_STRING:
- ret = Py_BuildValue("s", Z_STRVAL_PP(val));
- break;
- case IS_ARRAY:
- {
- PyObject *tuple, *dict, *item, *str;
- zval **entry;
- char *string_key;
- long num_key, string_counter = 0;
- /*
- * Start by building both a tuple and a dictionary. Because we
- * don't know with any certainty whether the array we've been
- * given is associative, we must create both a sequence and a
- * mapping.
- *
- * If, at the end of the conversion, we find that the original
- * array did _not_ contain any string keys, we return the tuple
- * instead of the dictionary.
- */
- tuple = PyTuple_New(zend_hash_num_elements(Z_ARRVAL_PP(val)));
- dict = PyDict_New();
- /* Let's start at the very beginning, a very good place to start */
- zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
- /* Iterate over the array's elements */
- while (zend_hash_get_current_data(Z_ARRVAL_PP(val),
- (void **)&entry) == SUCCESS) {
- /* Convert the PHP value to its Python equivalent (recursion) */
- item = convert_zval_to_pyobject(entry);
- switch (zend_hash_get_current_key(Z_ARRVAL_PP(val),
- &string_key, &num_key, 0)) {
- case HASH_KEY_IS_STRING:
- PyDict_SetItemString(dict, string_key, item);
- string_counter++;
- break;
- case HASH_KEY_IS_LONG:
- PyTuple_SetItem(tuple, num_key, item);
- str = PyString_FromFormat("%d", num_key);
- PyDict_SetItem(dict, str, item);
- Py_DECREF(str);
- break;
- case HASH_KEY_NON_EXISTANT:
- php_error(E_ERROR, "No array key");
- break;
- }
- /* Advance to the next entry */
- zend_hash_move_forward(Z_ARRVAL_PP(val));
- }
- /*
- * If no string keys were used, return the tuple and free the
- * dictionary. Otherwise, return the dictionary and free the
- * tuple.
- */
- if (string_counter == 0) {
- ret = tuple;
- Py_DECREF(dict);
- } else {
- ret = dict;
- Py_DECREF(tuple);
- }
- }
- break;
- case IS_OBJECT:
- {
- PyObject *item, *str;
- zval **entry;
- char *string_key;
- long num_key;
- /*
- * At this point, we represent a PHP object as a dictionary of
- * its properties. In the future, we may provide a true object
- * conversion (which is entirely possible, but it's more work
- * that I plan on doing right now).
- */
- ret = PyDict_New();
- /* Start at the beginning of the object properties hash */
- zend_hash_internal_pointer_reset(Z_OBJPROP_PP(val));
- while (zend_hash_get_current_data(Z_OBJPROP_PP(val),
- (void **)&entry) == SUCCESS) {
- /* Convert the PHP value to its Python equivalent (recursion) */
- item = convert_zval_to_pyobject(entry);
- switch (zend_hash_get_current_key(Z_OBJPROP_PP(val),
- &string_key, &num_key, 0)) {
- case HASH_KEY_IS_STRING:
- PyDict_SetItemString(ret, string_key, item);
- break;
- case HASH_KEY_IS_LONG:
- str = PyString_FromFormat("%d", num_key);
- PyObject_SetItem(ret, str, item);
- Py_DECREF(str);
- break;
- case HASH_KEY_NON_EXISTANT:
- php_error(E_ERROR, "No array key");
- break;
- }
- /* Advance to the next entry */
- zend_hash_move_forward(Z_OBJPROP_PP(val));
- }
- }
- break;
- case IS_NULL:
- Py_INCREF(Py_None);
- ret = Py_None;
- break;
- default:
- ret = NULL;
- break;
- }
- return ret;
- }