diff options
-rw-r--r-- | documentation/ten-reasons-for-using-php-cpp.html | 2 | ||||
-rw-r--r-- | include/call.h | 8 | ||||
-rw-r--r-- | zend/eval.cpp | 68 | ||||
-rw-r--r-- | zend/exists.cpp | 68 | ||||
-rw-r--r-- | zend/hashiterator.h | 16 | ||||
-rw-r--r-- | zend/value.cpp | 4 |
6 files changed, 158 insertions, 8 deletions
diff --git a/documentation/ten-reasons-for-using-php-cpp.html b/documentation/ten-reasons-for-using-php-cpp.html index 484f3fb..7d830d4 100644 --- a/documentation/ten-reasons-for-using-php-cpp.html +++ b/documentation/ten-reasons-for-using-php-cpp.html @@ -71,7 +71,7 @@ C++ is a proven language with a more than 40 year long history. C++ has an official open standard and is controlled by a C++ standards committee with members that have proven track records. Compilers have been developed by companies - like Microsoft, IBM, Intel, Apple and there there are several open source + like Microsoft, IBM, Intel, Apple and there are several open source compilers available (GNU, CLANG), so you can always switch to a faster or more stable alternative. The compiler vendors are constantly motivated to be better than their competitors and bring out new versions of their compilers diff --git a/include/call.h b/include/call.h index 16de1fe..e1bb12d 100644 --- a/include/call.h +++ b/include/call.h @@ -13,6 +13,14 @@ namespace Php { /** + * List of functions that are available for use in PHP + */ +extern bool class_exists(const char *classname, size_t size, bool autoload = true); +inline bool class_exists(const char *classname, bool autoload = true) { return class_exists(classname, strlen(classname), autoload); } +inline bool class_exists(const std::string &classname, bool autoload = true) { return class_exists(classname.c_str(), classname.size(), autoload); } +extern Value eval(const std::string &phpCode); + +/** * Call a function in PHP * @param name Name of the function to call * @param params Variable number of parameters diff --git a/zend/eval.cpp b/zend/eval.cpp new file mode 100644 index 0000000..4632fff --- /dev/null +++ b/zend/eval.cpp @@ -0,0 +1,68 @@ +/** + * Eval.cpp + * + * This file holds the implementation for the Php::eval() function + * + * @author andot <https://github.com/andot> + */ + +/** + * Dependencies + */ +#include "includes.h" + +/** + * Open PHP namespace + */ +namespace Php { + +/** + * Evaluate a PHP string + * @param phpCode The PHP code to evaluate + * @return Value The result of the evaluation + */ +Value eval(const std::string &phpCode) +{ + // we need the tsrm_ls variable + TSRMLS_FETCH(); + + // the current exception + zval* oldException = EG(exception); + + // the return zval + zval* retval = nullptr; + if (zend_eval_stringl_ex((char *)phpCode.c_str(), (int32_t)phpCode.length(), retval, (char *)"", 1 TSRMLS_CC) != SUCCESS) + { + // Do we want to throw an exception here? The original author + // did, but there are some reasons not to: + // + // 1. the PHP eval() function also does not throw exceptions. + // + // 2. the zend_eval_string() function already triggers a + // 'PHP parse error' when an error occurs, which also has + // to be handled. If we also throw an exception here, the + // user will have to write two error checks: for the error + // and the exception. + // + // if we _do_ want to throw an exception, we will first have to + // prevent the original zend_error to occur, and then turn it + // into an exception. An exception would be nicer from a C++ + // point of view, but because of the extra complexity, we do not + // this for now. + return nullptr; + } + else + { + // was an exception thrown inside the eval()'ed code? In that case we + // throw a C++ new exception to give the C++ code the chance to catch it + if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC); + + // no (additional) exception was thrown + return retval ? Value(retval) : nullptr; + } +} + +/** + * End of namespace + */ +} diff --git a/zend/exists.cpp b/zend/exists.cpp new file mode 100644 index 0000000..3add227 --- /dev/null +++ b/zend/exists.cpp @@ -0,0 +1,68 @@ +/** + * Exists.cpp + * + * This file holds the implementation of all *_exists() functions, + * like class_exists(), et cetera + * + * @author andot <https://github.com/andot> + */ + +/** + * Dependencies + */ +#include "includes.h" + +/** + * Open the PHP namespace + */ +namespace Php { + +/** + * Check whether a class with a certain name exists + * @param classname + * @param len + * @param autoload + * @return bool + */ +bool class_exists(const char *classname, size_t len, bool autoload) +{ + // we need the tsrm_ls variable + TSRMLS_FETCH(); + + // we're going to load a class-entry + zend_class_entry **ce; + + // should we autoload the class? + if (autoload) + { + // no auto-load + if (SUCCESS != zend_lookup_class(classname, len, &ce TSRMLS_CC)) return false; + + // the found "class" could also be an interface or trait, which we do no want + return ((*ce)->ce_flags & (ZEND_ACC_INTERFACE | (ZEND_ACC_TRAIT - ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) == 0; + } + else + { + // starting slashes can be ignored + if (len > 0 && classname[0] == '\\') { classname++; len--; } + + // all classes are in lowercase in the hash, so we make + // a temporary buffer for storing the lowercase class name + // (is this smart? memory allocation is expensive!) + std::unique_ptr<char[]> lc_name(new char[len + 1]); + + // copy the name to lowercase, but ignore the starting slash (if there is one) + zend_str_tolower_copy(lc_name.get(), classname, len); + + // see if there is a class with this name + if (SUCCESS != zend_hash_find(EG(class_table), lc_name.get(), len + 1, (void **) &ce)) return false; + + // the found "class" could also be an interface or trait, which we do no want + return !(((*ce)->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT)) > ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); + } +} + +/** + * End of namespace + */ +} diff --git a/zend/hashiterator.h b/zend/hashiterator.h index b1f409f..36c3d6c 100644 --- a/zend/hashiterator.h +++ b/zend/hashiterator.h @@ -29,7 +29,7 @@ public: * @param first Should it start on the first position? * @param tsrm_ls */ - HashIterator(HashTable *hashtable, bool first) : _table(hashtable) + HashIterator(HashTable *hashtable, bool first, bool is_array = false) : _table(hashtable), _is_array(is_array) { // reset the hash pointer to the internal position if (hashtable && first) @@ -56,7 +56,7 @@ public: * @param tsrm_ls */ HashIterator(const HashIterator &that TSRMLS_DC) : - _table(that._table), _position(that._position) + _table(that._table), _position(that._position), _is_array(that._is_array) { // read current position read(); @@ -166,7 +166,13 @@ private: * @var HashPosition */ Bucket *_position = nullptr; - + + /** + * Is a hash interator in array + * @var bool + */ + bool _is_array = false; + /** * The current key and value * @var std::pair @@ -207,7 +213,7 @@ private: // numeric keys are the easiest ones if (type == HASH_KEY_IS_LONG) key = (int64_t)num_key; - else key = string_key; + else key = std::string(string_key, str_len - 1); #endif @@ -223,7 +229,7 @@ private: // if the key is private (it starts with a null character) we should return // false to report that the object is not in a completely valid state - return !_current.first.isString() || _current.first.rawValue()[0]; + return _is_array || !_current.first.isString() || _current.first.rawValue()[0]; } /** diff --git a/zend/value.cpp b/zend/value.cpp index 38a0425..9b409f7 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -1664,7 +1664,7 @@ std::map<std::string,Php::Value> Value::mapValue() const ValueIterator Value::createIterator(bool begin) const { // check type - if (isArray()) return ValueIterator(new HashIterator(Z_ARRVAL_P(_val), begin)); + if (isArray()) return ValueIterator(new HashIterator(Z_ARRVAL_P(_val), begin, true)); // get access to the hast table if (isObject()) @@ -1685,7 +1685,7 @@ ValueIterator Value::createIterator(bool begin) const else { // construct a regular iterator - return ValueIterator(new HashIterator(Z_OBJ_HT_P(_val)->get_properties(_val TSRMLS_CC), begin)); + return ValueIterator(new HashIterator(Z_OBJPROP_P(_val), begin)); } } |