diff options
author | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-06-19 13:49:07 +0200 |
---|---|---|
committer | Emiel Bruijntjes <emiel.bruijntjes@copernica.com> | 2014-06-19 13:49:07 +0200 |
commit | ca60a32c601fe9b0236d3d4717c7b94368a3c172 (patch) | |
tree | 882756690ee8e446f7fc9e3ba14313151eddf423 | |
parent | c6c68cbc60711b43e8a570d708db3768240fcc5a (diff) |
errors are no longer thrown as exceptions, but are php fatal errors, so that they more closely match the zend error reporting system
-rw-r--r-- | include/array.h | 10 | ||||
-rw-r--r-- | include/exception.h | 10 | ||||
-rw-r--r-- | include/object.h | 8 | ||||
-rw-r--r-- | phpcpp.h | 1 | ||||
-rw-r--r-- | zend/classimpl.cpp | 18 | ||||
-rw-r--r-- | zend/includes.h | 1 | ||||
-rw-r--r-- | zend/object.cpp | 18 | ||||
-rw-r--r-- | zend/origexception.h | 6 | ||||
-rw-r--r-- | zend/streambuf.cpp | 3 | ||||
-rw-r--r-- | zend/value.cpp | 50 |
10 files changed, 81 insertions, 44 deletions
diff --git a/include/array.h b/include/array.h index 0b6ceb9..4d6b6b1 100644 --- a/include/array.h +++ b/include/array.h @@ -31,7 +31,7 @@ public: Array(const Value &value) : Value(value) { // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to an array variable"); + if (value.type() != Type::Array) throw FatalError("Assigning a non-array to an array variable"); } /** @@ -41,7 +41,7 @@ public: Array(Value &&value) : Value(std::move(value)) { // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to an array variable"); + if (value.type() != Type::Array) throw FatalError("Moving a non-array to an array variable"); } /** @@ -76,7 +76,7 @@ public: virtual Value &setType(Type type) override { // throw exception if things are going wrong - if (type != Type::Array) throw Php::Exception("Changing type of a fixed array variable"); + if (type != Type::Array) throw FatalError("Changing type of a fixed array variable"); // call base return Value::setType(Type::Array); @@ -93,7 +93,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to a fixed array variable"); + if (value.type() != Type::Array) throw FatalError("Assigning a non-array to a fixed array variable"); // call base Value::operator=(value); @@ -113,7 +113,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to a fixed array variable"); + if (value.type() != Type::Array) throw FatalError("Moving a non-array to a fixed array variable"); // call base Value::operator=(std::move(value)); diff --git a/include/exception.h b/include/exception.h index 671df9e..aff0afc 100644 --- a/include/exception.h +++ b/include/exception.h @@ -75,6 +75,16 @@ public: // yes, it is native return true; } + + /** + * Report this error as a fatal error + * @return bool + */ + virtual bool report() const + { + // this is not done here + return false; + } }; /** diff --git a/include/object.h b/include/object.h index 97c9482..2e6628a 100644 --- a/include/object.h +++ b/include/object.h @@ -31,7 +31,7 @@ public: Object(Value &&value) : Value(std::move(value)) { // throw exception in case of problems - if (value.type() != Type::Object) throw Php::Exception("Constructing an object variable by moving a non object"); + if (value.type() != Type::Object) throw FatalError("Constructing an object variable by moving a non object"); } /** @@ -123,7 +123,7 @@ public: virtual Value &setType(Type type) override { // throw exception if things are going wrong - if (type != Type::Object) throw Php::Exception("Changing type of a fixed object variable"); + if (type != Type::Object) throw FatalError("Changing type of a fixed object variable"); // call base return Value::setType(type); @@ -140,7 +140,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Object) throw Php::Exception("Assigning a non-object to an object variable"); + if (value.type() != Type::Object) throw FatalError("Assigning a non-object to an object variable"); // call base Value::operator=(value); @@ -160,7 +160,7 @@ public: if (this == &value) return *this; // type must be valid - if (value.type() != Type::Object) throw Php::Exception("Moving a non-object to an object variable"); + if (value.type() != Type::Object) throw FatalError("Moving a non-object to an object variable"); // call base Value::operator=(std::move(value)); @@ -29,6 +29,7 @@ #include <phpcpp/inivalue.h> #include <phpcpp/ini.h> #include <phpcpp/exception.h> +#include <phpcpp/fatalerror.h> #include <phpcpp/streams.h> #include <phpcpp/type.h> #include <phpcpp/hashparent.h> diff --git a/zend/classimpl.cpp b/zend/classimpl.cpp index 953738a..ca75c5e 100644 --- a/zend/classimpl.cpp +++ b/zend/classimpl.cpp @@ -524,8 +524,10 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC) // report error on failure (this does not occur because the cloneObject() // method is only installed as handler when we have seen that there is indeed - // a copy constructor) - if (!cpp) throw Php::Exception(std::string("Unable to clone ") + entry->name); + // a copy constructor). Because this function is directly called from the + // Zend engine, we can call zend_error() (which does a longjmp()) to throw + // an exception back to the Zend engine) + if (!cpp) zend_error(E_ERROR, "Unable to clone %s", entry->name); // the thing we're going to return zend_object_value result; @@ -1183,8 +1185,10 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC) // create a new base C++ object auto *cpp = impl->_base->construct(); - // report error on failure - if (!cpp) throw Php::Exception(std::string("Unable to instantiate ") + entry->name); + // report error on failure, because this function is called directly from the + // Zend engine, we can call zend_error() here (which does a longjmp() back to + // the Zend engine) + if (!cpp) zend_error(E_ERROR, "Unable to instantiate %s", entry->name); // the thing we're going to return zend_object_value result; @@ -1212,8 +1216,10 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC) */ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *object, int by_ref TSRMLS_DC) { - // by-ref is not possible (copied from SPL) - if (by_ref) throw Php::Exception("Foreach by ref is not possible"); + // by-ref is not possible (copied from SPL), this function is called directly + // from the Zend engine, so we can use zend_error() to longjmp() back to the + // Zend engine) + if (by_ref) zend_error(E_ERROR, "Foreach by ref is not possible"); // retrieve the traversable object Traversable *traversable = dynamic_cast<Traversable*>(ObjectImpl::find(object TSRMLS_CC)->object()); diff --git a/zend/includes.h b/zend/includes.h index cabb096..63b435e 100644 --- a/zend/includes.h +++ b/zend/includes.h @@ -48,6 +48,7 @@ #include "../include/inivalue.h" #include "../include/ini.h" #include "../include/exception.h" +#include "../include/fatalerror.h" #include "../include/streams.h" #include "../include/type.h" #include "../include/hashparent.h" diff --git a/zend/object.cpp b/zend/object.cpp index 940b143..dc548cc 100644 --- a/zend/object.cpp +++ b/zend/object.cpp @@ -32,9 +32,12 @@ Object::Object(const char *name, Base *base) // this is a brand new object that should be allocated, the C++ instance // is already there (created by the extension) but it is not yet stored - // in PHP, find out the classname first - auto *entry = zend_fetch_class(name, ::strlen(name), 0 TSRMLS_CC); - if (!entry) throw Php::Exception(std::string("Unknown class name ") + name); + // in PHP, find out the classname first (we use the FatalError class + // here because this function is called from C++ context, and zend_error() + // would cause a longjmp() which does not clean up C++ objects created + // by the extension). + auto *entry = zend_fetch_class(name, ::strlen(name), ZEND_FETCH_CLASS_SILENT TSRMLS_CC); + if (!entry) throw FatalError(std::string("Unknown class name ") + name); // construct an implementation (this will also set the implementation // member in the base object) @@ -57,9 +60,12 @@ void Object::instantiate(const char *name) // we need the tsrm_ls variable TSRMLS_FETCH(); - // convert the name into a class_entry - auto *entry = zend_fetch_class(name, ::strlen(name), 0 TSRMLS_CC); - if (!entry) throw Php::Exception(std::string("Unknown class name ") + name); + // convert the name into a class_entry (we use the FatalError class + // here because this function is called from C++ context, and zend_error() + // would cause a longjmp() which does not clean up C++ objects created + // by the extension). + auto *entry = zend_fetch_class(name, ::strlen(name), ZEND_FETCH_CLASS_SILENT TSRMLS_CC); + if (!entry) throw FatalError(std::string("Unknown class name ") + name); // initiate the zval (which was already allocated in the base constructor) object_init_ex(_val, entry); diff --git a/zend/origexception.h b/zend/origexception.h index 775e412..55f89cf 100644 --- a/zend/origexception.h +++ b/zend/origexception.h @@ -127,10 +127,12 @@ inline void process(Exception &exception TSRMLS_DC) // the exception is native, call the zend throw method zend_throw_exception(zend_exception_get_default(TSRMLS_C), (char *)exception.what(), 0 TSRMLS_CC); } - else + + // or does it have its own report function? + else if (!exception.report()) { // this is not a native exception, so it was originally thrown by a - // php script, and then not caught by the c++ of the extensiont, we are + // php script, and then not caught by the c++ of the extension, we are // going to tell to the exception that it is still active OrigException &orig = static_cast<OrigException&>(exception); diff --git a/zend/streambuf.cpp b/zend/streambuf.cpp index 86e5f03..11d928d 100644 --- a/zend/streambuf.cpp +++ b/zend/streambuf.cpp @@ -33,7 +33,6 @@ int StreamBuf::sync() // not null terminated and (2) it could contain % signs and allow all // sorts of buffer overflows. zend_error(_error, "%.*s", (int)size, pbase()); - } else { @@ -52,4 +51,4 @@ int StreamBuf::sync() * End namespace */ } -
\ No newline at end of file + diff --git a/zend/value.cpp b/zend/value.cpp index 6458bd5..9a1a5db 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -192,7 +192,7 @@ Value::Value(const Base *object) auto *impl = object->implementation(); // do we have a handle? - if (!impl) throw Php::Exception("Assigning an unassigned object to a variable"); + if (!impl) throw FatalError("Assigning an unassigned object to a variable"); // make a regular zval, and set it to an object MAKE_STD_ZVAL(_val); @@ -1317,28 +1317,37 @@ Value Value::exec(const char *name, int argc, struct _zval_struct ***params) */ bool Value::operator==(const Value &value) const { + // we need the tsrm_ls variable + TSRMLS_FETCH(); + + // zval that will hold the result of the comparison zval result; - if(SUCCESS != compare_function(&result, _val, value._val TSRMLS_CC) ) - { - throw Php::Exception("Not comparable"); - return false; - } - return (0 == result.value.lval); + + // run the comparison + if (SUCCESS != compare_function(&result, _val, value._val TSRMLS_CC)) return false; + + // convert to boolean + return result.value.lval == 0; } /** * Comparison operators< for hardcoded Value * @param value + * @return bool */ -bool Value::operator< (const Value &value) const +bool Value::operator<(const Value &value) const { + // we need the tsrm_ls variable + TSRMLS_FETCH(); + + // zval that will hold the result of the comparison zval result; - if(SUCCESS != compare_function(&result, _val, value._val TSRMLS_CC) ) - { - throw Php::Exception("Not comparable"); - return false; - } - return (-1 == result.value.lval); + + // run the comparison + if (SUCCESS != compare_function(&result, _val, value._val TSRMLS_CC)) return false; + + // convert to boolean + return result.value.lval < 0; } /** @@ -1364,7 +1373,10 @@ Value &Value::setType(Type type) // if this is not a reference variable, we should detach it to implement copy on write SEPARATE_ZVAL_IF_NOT_REF(&_val); - // run the conversion + // run the conversion, when it fails we throw a fatal error which will + // in the end result in a zend_error() call. This FatalError class is necessary + // because a direct call to zend_error() will do a longjmp() which may not + // clean up the C++ objects created by the extension switch (type) { case Type::Null: convert_to_null(_val); break; case Type::Numeric: convert_to_long(_val); break; @@ -1373,10 +1385,10 @@ Value &Value::setType(Type type) case Type::Array: convert_to_array(_val); break; case Type::Object: convert_to_object(_val); break; case Type::String: convert_to_string(_val); break; - case Type::Resource: throw Php::Exception("Resource types can not be handled by the PHP-CPP library"); break; - case Type::Constant: throw Php::Exception("Constant types can not be assigned to a PHP-CPP library variable"); break; - case Type::ConstantArray: throw Php::Exception("Constant types can not be assigned to a PHP-CPP library variable"); break; - case Type::Callable: throw Php::Exception("Callable types can not be assigned to a PHP-CPP library variable"); break; + case Type::Resource: throw FatalError("Resource types can not be handled by the PHP-CPP library"); break; + case Type::Constant: throw FatalError("Constant types can not be assigned to a PHP-CPP library variable"); break; + case Type::ConstantArray: throw FatalError("Constant types can not be assigned to a PHP-CPP library variable"); break; + case Type::Callable: throw FatalError("Callable types can not be assigned to a PHP-CPP library variable"); break; } // done |