From 7f6af2fb9c1bcabbe969fd8f6fb56907ba5a2367 Mon Sep 17 00:00:00 2001 From: andot Date: Thu, 10 Jul 2014 17:28:00 +0800 Subject: [PATCH 1/2] Add keys method for Php::Value This method can get the array keys, or object property names, include private & protected properties. It is similar to working in PHP: array_keys($array); and array_keys((array)$object); but the return value type is std::vector, and it's faster than using php function. --- include/value.h | 6 ++++++ zend/value.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/value.h b/include/value.h index f72304cf..e43cc582 100644 --- a/include/value.h +++ b/include/value.h @@ -507,6 +507,12 @@ class Value : private HashParent return result; } + /** + * Get array keys, or object property names, include private & protected properties + * @return std::vector + */ + std::vector keys() const; + /** * Define the iterator type */ diff --git a/zend/value.cpp b/zend/value.cpp index 9a1a5dbb..fd3701ee 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -1618,6 +1618,59 @@ std::map Value::mapValue() const return result; } +/** + * Get array keys, or object property names, include private & protected properties + * @return std::vector + */ +std::vector Value::keys() const { + if (!isArray() && !isObject()) return std::vector(); + + std::vector result; + + HashTable *table = isArray() ? Z_ARRVAL_P(_val) : Z_OBJPROP_P(_val); + + Bucket *position = nullptr; + + // move to first position + zend_hash_internal_pointer_reset_ex(table, &position); + + do { + + // zval to read the current key in + Value key; + +#if PHP_VERSION_ID >= 50500 + // read in the current key + zend_hash_get_current_key_zval_ex(table, key._val, &position); + + // if the key is set to NULL, it means that the object is not at a valid position + if (key.isNull()) continue; +#else + // php 5.3 and php 5.4 need a different implementation because the function + // zend_hash_get_current_key_zval_ex is missing in php 5.3, declare variables + // we need for storing the key in + char *string_key; + unsigned int str_len; + unsigned long num_key; + + // get the current key + int type = zend_hash_get_current_key_ex(table, &string_key, &str_len, &num_key, 0, &position); + + // if key is not found, the iterator is at an invalid position + if (type == HASH_KEY_NON_EXISTANT) continue; + + // numeric keys are the easiest ones + if (type == HASH_KEY_IS_LONG) key = (int64_t)num_key; + else key = std::string(string_key, str_len - 1); +#endif + result.push_back(std::move(key)); + + // move the iterator forward + } while (zend_hash_move_forward_ex(table, &position) == SUCCESS); + + return result; +} + /** * Internal helper method to retrieve an iterator * @param begin Should the iterator start at the begin From 856070c9dd3f6219aec1856fa4ac3fdc98f86c6d Mon Sep 17 00:00:00 2001 From: andot Date: Sat, 19 Jul 2014 18:07:33 +0800 Subject: [PATCH 2/2] optimized the implementation of keys. --- zend/value.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zend/value.cpp b/zend/value.cpp index fd3701ee..d40ab3cc 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -1629,6 +1629,8 @@ std::vector Value::keys() const { HashTable *table = isArray() ? Z_ARRVAL_P(_val) : Z_OBJPROP_P(_val); + result.reserve(zend_hash_num_elements(table)); + Bucket *position = nullptr; // move to first position