diff --git a/include/value.h b/include/value.h index f72304cf..520b585d 100644 --- a/include/value.h +++ b/include/value.h @@ -507,6 +507,13 @@ class Value : private HashParent return result; } + /** + * Get object property names. + * @param only_public + * @return std::vector + */ + std::vector properties(bool only_public = true) const; + /** * Define the iterator type */ diff --git a/zend/includes.h b/zend/includes.h index 63b435eb..9d138367 100644 --- a/zend/includes.h +++ b/zend/includes.h @@ -20,7 +20,8 @@ #include #include #include - +#include + // for debug #include diff --git a/zend/value.cpp b/zend/value.cpp index 9a1a5dbb..b9b98c8e 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -1618,6 +1618,52 @@ std::map Value::mapValue() const return result; } +/** + * Get object property names. + * @param only_public + * @return std::vector + */ +std::vector Value::properties(bool only_public) const { + if (isObject()) { + std::set result; + + // we need the TSRMLS_CC variable + TSRMLS_FETCH(); + + HashTable *table = Z_OBJPROP_P(_val); + Bucket *position = nullptr; + + // move to first position + zend_hash_internal_pointer_reset_ex(table, &position); + + do { + 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; + + std::string key = std::string(string_key, str_len - 1); + if (key[0] == '\0') { + // if only_public is true, only store public property + if (only_public) continue; + key = key.substr(key.find('\0', 1) + 1); + } + result.insert(std::move(key)); + + // move the iterator forward + } while (zend_hash_move_forward_ex(table, &position) == SUCCESS); + + return std::vector(result.begin(), result.end()); + + } + return std::vector(); +} + /** * Internal helper method to retrieve an iterator * @param begin Should the iterator start at the begin