diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-09 18:21:12 +0100 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-03-09 18:21:12 +0100 |
commit | b2a054d0b01fc6fbf00dd93efed8f2e19426a02a (patch) | |
tree | 9d23854ec117c151934daaec9141bf4e36e49e13 | |
parent | 8e9d929a752775883e3a7379bb7372299d40255d (diff) | |
parent | 5a186cc932524d85ce602e152a79d5201a4eb3b5 (diff) |
Merge branch 'issue23' of https://github.com/valmat/PHP-CPP
-rw-r--r-- | Examples/CppClassesInPhp/check_map.php | 86 | ||||
-rw-r--r-- | Examples/CppClassesInPhp/cppclassinphp.cpp | 18 | ||||
-rw-r--r-- | src/value.cpp | 81 |
3 files changed, 164 insertions, 21 deletions
diff --git a/Examples/CppClassesInPhp/check_map.php b/Examples/CppClassesInPhp/check_map.php new file mode 100644 index 0000000..2103bac --- /dev/null +++ b/Examples/CppClassesInPhp/check_map.php @@ -0,0 +1,86 @@ +<?php + +/** + * For functionality testing. You can then delete. + * + */ + +class cl0 { + public $cl0_float = 3.14; + public $cl0_str1 = 'public str1'; + private $cl0_str2 = 'private str2'; + protected $cl0_str3 = 'protected str3'; +} + +class cl1 extends cl0 implements arrayaccess +{ + static $cl1_static = 'static prop'; + + const CL1_CONST = 'const prop'; + + public $cl1_num = 45615; + public $cl1_str = "Public Prop"; + + private $cl1_pp1 = "Private Prop1"; + private $cl1_pp2 = "Private Prop2"; + + protected $cl1_prp1 = "Protected Prop1"; + protected $cl1_prp2 = "Protected Prop2"; + + public function fn($a) { + echo $a; + } + + function __toString() { + return 'I\'m class cl1'; + } + + public function offsetSet($offset, $value) { + if (!is_null($offset)) { + $this->$offset = $value; + } + } + public function offsetExists($offset) { + return isset($this->$offset); + } + public function offsetUnset($offset) { + unset($this->$offset); + } + public function offsetGet($offset) { + return isset($this->$offset) ? $this->$offset : null; + } + +} + +class emptyClass {} + +$arr = array( + 'qwe' => 'qweqweqweqw', + 'asd' => 'Привет!', // check UTF-8 chars + 'zxccvx' => 'sdfsecvyh6bug6yfty', + 1=>2, + '2'=>2, + 44, + new cl1(), + '%'=>'%$%$%', + ); + +$arr = new cl1(); + +$arr[5] = 55; +$arr['strstr'] = 'strstrstrstrstrstr'; + +//$arr = new emptyClass(); +//$arr = array(); + + +$q = new MyClass(); + +var_export($arr); + +//$q->loopArray($arr); + +// Works for objects and arrays +$q->loopObject($arr); +//$q->loopObject($arr); + diff --git a/Examples/CppClassesInPhp/cppclassinphp.cpp b/Examples/CppClassesInPhp/cppclassinphp.cpp index 400d942..9a4e130 100644 --- a/Examples/CppClassesInPhp/cppclassinphp.cpp +++ b/Examples/CppClassesInPhp/cppclassinphp.cpp @@ -51,6 +51,17 @@ public: { return 33; } + + void loop(Php::Parameters ¶ms) + { + std::cout << "Array/Object contains " << params[0].size() << " items" << std::endl; + auto m = params[0].mapValue(); + + std::cout << "map contains " << m.size() << " items" << std::endl; + for(auto &i: m) { + std::cout << "key: " << i.first << " \t\tval: " << i.second << std::endl; + } + } Php::Value myMethod(Php::Parameters ¶ms) { @@ -124,6 +135,13 @@ extern "C" customClass.method("myMethod2", &MyCustomClass::myMethod); customClass.property("property1", "prop1"); customClass.property("property2", "prop2", Php::Protected); + + customClass.method("loopArray", &MyCustomClass::loop, { + Php::ByVal("arr", Php::Type::Array) + }); + customClass.method("loopObject", &MyCustomClass::loop, { + Php::ByVal("obj", Php::Type::Object) + }); // add the class to the extension extension.add(customClass); diff --git a/src/value.cpp b/src/value.cpp index 2afb750..752d77e 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1467,32 +1467,71 @@ int Value::size() const */ std::map<std::string,Php::Value> Value::mapValue() const { + // loop through the zval key/value pairs, and return a map + // result variable + std::map<std::string,Php::Value> result; + // check type - if (isArray()) + if (isArray() || isObject()) { - // result variable - std::map<std::string,Php::Value> result; - - // @todo loop through the zval key/value pairs, and return a map + zval **value; + char *key; + unsigned long ind; - // done - return result; - } - else if (isObject()) - { - // result variable - std::map<std::string,Php::Value> result; - - // @todo convert the properties to a map + // get access to the internal hash table of _val + // see Zend/zend_API.h 723: HASH_OF(_val) + HashTable *arr = isArray() ? Z_ARRVAL_P(_val) : Z_OBJ_HT_P(_val)->get_properties((_val) TSRMLS_CC); - // done - return result; - } - else - { - // return an empty map - return std::map<std::string,Php::Value>(); + + // similarly php: reset($array): + // The definition of this and the following functions can be found in Zend/zend_hash.h 174 + // Maybe make it optional? + // If the following line to remove, then repeated calling the Value::mapValue() will return an empty map + zend_hash_internal_pointer_reset(arr); + + if (isArray()) + { + unsigned int hash_key_type; + while( (hash_key_type = zend_hash_get_current_key(arr, &key, &ind, 0)) != HASH_KEY_NON_EXISTENT ) + { + zend_hash_get_current_data(arr, (void **) &value); + + if(HASH_KEY_IS_LONG == hash_key_type) + { + result[std::to_string(ind)] = Value(*value); + } + else // hash_key_type == HASH_KEY_IS_STRING + { + result[key] = Value(*value); + } + + // next iteration + zend_hash_move_forward(arr); + } + } + else + { + // For obtaining a hashtable of the object meets function void rebuild_object_properties(zend_object *zobj) + // Zend/zend_object_handlers.c 66 + // hashtable of object's properties always has string (no integer) keys + while( zend_hash_get_current_key(arr, &key, &ind, 0) != HASH_KEY_NON_EXISTENT ) + { + // if propertie is accessible (i.e. propertie access type is public. See rebuild_object_properties ) + if('\0' != *key) + { + zend_hash_get_current_data(arr, (void **) &value); + result[key] = Value(*value); + } + + // next iteration + zend_hash_move_forward(arr); + } + } + } + + // done + return result; } /** |