summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/array.h10
-rw-r--r--include/exception.h10
-rw-r--r--include/object.h8
-rw-r--r--phpcpp.h1
-rw-r--r--zend/classimpl.cpp18
-rw-r--r--zend/includes.h1
-rw-r--r--zend/object.cpp18
-rw-r--r--zend/origexception.h6
-rw-r--r--zend/streambuf.cpp3
-rw-r--r--zend/value.cpp50
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));
diff --git a/phpcpp.h b/phpcpp.h
index 3f94cef..c3f3365 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -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