summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile71
-rw-r--r--common/extensionbase.h138
-rw-r--r--common/includes.h23
-rw-r--r--common/modifiers.cpp (renamed from src/modifiers.cpp)0
-rw-r--r--common/streambuf.cpp (renamed from src/streambuf.cpp)33
-rw-r--r--common/streambuf.h (renamed from src/streambuf.h)0
-rw-r--r--config/config.cpp28
-rw-r--r--documentation/ten-reasons-for-using-php-cpp.html4
-rw-r--r--hhvm/extension.cpp103
-rw-r--r--hhvm/extensionimpl.h55
-rw-r--r--hhvm/includes.h55
-rw-r--r--hhvm/streambuf.cpp59
-rw-r--r--hhvm/streams.cpp41
-rw-r--r--include/argument.h111
-rw-r--r--include/array.h4
-rw-r--r--include/base.h42
-rw-r--r--include/class.h5
-rw-r--r--include/exception.h37
-rw-r--r--include/extension.h129
-rw-r--r--include/iterator.h102
-rw-r--r--include/namespace.h178
-rw-r--r--include/object.h2
-rw-r--r--include/parameters.h29
-rw-r--r--include/value.h3
-rw-r--r--include/valueiterator.h12
-rw-r--r--phpcpp.h26
-rw-r--r--src/argument.cpp171
-rw-r--r--src/exception.cpp34
-rw-r--r--src/mixedobject.h39
-rw-r--r--src/origexception.cpp35
-rw-r--r--src/origexception.h79
-rw-r--r--src/parameters.cpp49
-rw-r--r--tests/php/phpt/variables/021-HashMember-3.phpt1
-rw-r--r--zend/arithmetic.h (renamed from src/arithmetic.h)0
-rw-r--r--zend/base.cpp (renamed from src/base.cpp)110
-rw-r--r--zend/boolmember.h (renamed from src/boolmember.h)0
-rw-r--r--zend/callable.cpp (renamed from src/callable.cpp)21
-rw-r--r--zend/callable.h (renamed from src/callable.h)75
-rw-r--r--zend/classbase.cpp (renamed from src/classbase.cpp)0
-rw-r--r--zend/classimpl.cpp (renamed from src/classimpl.cpp)194
-rw-r--r--zend/classimpl.h (renamed from src/classimpl.h)7
-rw-r--r--zend/extension.cpp103
-rw-r--r--zend/extensionimpl.cpp (renamed from src/extension.cpp)142
-rw-r--r--zend/extensionimpl.h120
-rw-r--r--zend/floatmember.h (renamed from src/floatmember.h)0
-rw-r--r--zend/function.h (renamed from src/function.h)2
-rw-r--r--zend/global.cpp (renamed from src/global.cpp)0
-rw-r--r--zend/globals.cpp (renamed from src/globals.cpp)0
-rw-r--r--zend/hashiterator.h (renamed from src/hashiterator.h)8
-rw-r--r--zend/hashmember.cpp (renamed from src/hashmember.cpp)0
-rw-r--r--zend/includes.h (renamed from src/includes.h)18
-rw-r--r--zend/init.h (renamed from include/init.h)0
-rw-r--r--zend/invaliditerator.h (renamed from src/invaliditerator.h)8
-rw-r--r--zend/iteratorimpl.cpp (renamed from src/iterator.cpp)93
-rw-r--r--zend/iteratorimpl.h190
-rw-r--r--zend/member.h (renamed from src/member.h)0
-rw-r--r--zend/members.cpp (renamed from src/members.cpp)0
-rw-r--r--zend/method.h (renamed from src/method.h)0
-rw-r--r--zend/namespace.cpp (renamed from src/namespace.cpp)79
-rw-r--r--zend/notimplemented.h (renamed from src/notimplemented.h)0
-rw-r--r--zend/nullmember.h (renamed from src/nullmember.h)0
-rw-r--r--zend/numericmember.h (renamed from src/numericmember.h)0
-rw-r--r--zend/object.cpp (renamed from src/object.cpp)7
-rw-r--r--zend/objectimpl.h207
-rw-r--r--zend/origexception.h145
-rw-r--r--zend/parametersimpl.h53
-rw-r--r--zend/property.h (renamed from src/property.h)0
-rw-r--r--zend/streambuf.cpp55
-rw-r--r--zend/streams.cpp (renamed from src/streams.cpp)0
-rw-r--r--zend/stringmember.h (renamed from src/stringmember.h)0
-rw-r--r--zend/super.cpp (renamed from src/super.cpp)0
-rw-r--r--zend/traverseiterator.h (renamed from src/traverseiterator.h)8
-rw-r--r--zend/value.cpp (renamed from src/value.cpp)18
-rw-r--r--zend/valueiterator.cpp (renamed from src/valueiterator.cpp)0
-rw-r--r--zend/valueiteratorimpl.h (renamed from src/iteratorimpl.h)18
75 files changed, 2046 insertions, 1333 deletions
diff --git a/Makefile b/Makefile
index ce4c59e..890f881 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,8 @@ INSTALL_LIB = ${INSTALL_PREFIX}/lib
# you can change that here.
#
-LIBRARY = libphpcpp.so
+PHP_LIBRARY = libphpcpp.so
+HHVM_LIBRARY = libhhvmcpp.so
#
@@ -84,7 +85,9 @@ LINKER = g++
# you want to leave that flag out on production servers).
#
-COMPILER_FLAGS = -Wall -c `php-config --includes` -g -std=c++11 -fpic -o
+COMPILER_FLAGS = -Wall -c -g -std=c++11 -fpic
+PHP_COMPILER_FLAGS = ${COMPILER_FLAGS} `php-config --includes`
+HHVM_COMPILER_FLAGS = ${COMPILER_FLAGS}
#
# Linker flags
@@ -96,7 +99,9 @@ COMPILER_FLAGS = -Wall -c `php-config --includes` -g -std=c++11 -fpic -o
# to the linker flags
#
-LINKER_FLAGS = -shared `php-config --ldflags`
+LINKER_FLAGS = -shared
+PHP_LINKER_FLAGS = ${LINKER_FLAGS} `php-config --ldflags`
+HHVM_LINKER_FLAGS = ${LINKER_FLAGS}
#
@@ -115,33 +120,26 @@ MKDIR = mkdir -p
# The source files
#
# For this we use a special Makefile function that automatically scans the
-# src/ directory for all *.cpp files. No changes are probably necessary here
+# common/, zend/ and hhvm/ directories for all *.cpp files. No changes are
+# probably necessary here
#
-LIBRARY_SOURCES = $(wildcard src/*.cpp)
-
+COMMON_SOURCES = $(wildcard common/*.cpp)
+PHP_SOURCES = $(wildcard zend/*.cpp)
+HHVM_SOURCES = $(wildcard hhvm/*.cpp)
#
# The object files
#
# The intermediate object files are generated by the compiler right before
-# the linker turns all these object files into the libphpcpp.so shared library.
-# We also use a Makefile function here that takes all source files.
+# the linker turns all these object files into the libphpcpp.so and
+# libhhvmcpp.so shared libraries. We also use a Makefile function here that
+# takes all source files.
#
-LIBRARY_OBJECTS = $(LIBRARY_SOURCES:%.cpp=%.o)
-
-
-#
-# Configuration program
-#
-# During installation, a configuration utility will be installed. It is
-# compiled with the following instructions
-#
-
-CONFIG_UTILITY = ./create_config
-CONFIG_SOURCES = $(wildcard config/*.cpp)
-CONFIG_FLAGS = `php-config --includes` -o
+COMMON_OBJECTS = $(COMMON_SOURCES:%.cpp=%.o)
+PHP_OBJECTS = $(PHP_SOURCES:%.cpp=%.o)
+HHVM_OBJECTS = $(HHVM_SOURCES:%.cpp=%.o)
#
@@ -149,29 +147,38 @@ CONFIG_FLAGS = `php-config --includes` -o
# dependencies that are used by the compiler.
#
-all: ${LIBRARY_OBJECTS} ${LIBRARY} ${CONFIG_UTILITY}
+all: ${PHP_LIBRARY}
+
+phpcpp: ${PHP_LIBRARY}
+
+hhvmcpp: ${HHVM_LIBRARY}
-${LIBRARY}: ${LIBRARY_OBJECTS}
- ${LINKER} ${LINKER_FLAGS} -o $@ ${LIBRARY_OBJECTS}
+${PHP_LIBRARY}: ${COMMON_OBJECTS} ${PHP_OBJECTS}
+ ${LINKER} ${PHP_LINKER_FLAGS} -o $@ ${COMMON_OBJECTS} ${PHP_OBJECTS}
-${CONFIG_UTILITY}:
- ${COMPILER} ${CONFIG_FLAGS} $@ ${CONFIG_SOURCES}
+${HHVM_LIBRARY}: ${COMMON_OBJECTS} ${HHVM_OBJECTS}
+ ${LINKER} ${HHVM_LINKER_FLAGS} -o $@ ${COMMON_OBJECTS} ${HHVM_OBJECTS}
clean:
- ${RM} ${LIBRARY_OBJECTS} ${LIBRARY} ${CONFIG_UTILITY}
+ ${RM} ${COMMON_OBJECTS} ${PHP_OBJECTS} ${HHVM_OBJECTS} ${PHP_LIBRARY} ${HHVM_LIBRARY}
+
+${COMMON_OBJECTS}:
+ ${COMPILER} ${COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
+
+${PHP_OBJECTS}:
+ ${COMPILER} ${PHP_COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
-${LIBRARY_OBJECTS}:
- ${COMPILER} ${COMPILER_FLAGS} $@ ${@:%.o=%.cpp}
+${HHVM_OBJECTS}:
+ ${COMPILER} ${HHVM_COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp}
install:
${MKDIR} ${INSTALL_HEADERS}/phpcpp
${CP} phpcpp.h ${INSTALL_HEADERS}
${CP} include/*.h ${INSTALL_HEADERS}/phpcpp
- ${CP} ${LIBRARY} ${INSTALL_LIB}
- ${CONFIG_UTILITY} > ${INSTALL_HEADERS}/phpcpp/config.h
+ if [ -e ${PHP_LIBRARY} ]; then ${CP} ${PHP_LIBRARY} ${INSTALL_LIB}; fi
+ if [ -e ${HHVM_LIBRARY} ]; then ${CP} ${HHVM_LIBRARY} ${INSTALL_LIB}; fi
test:
mkdir -p ./tests/include/zts/phpcpp
- ${CONFIG_UTILITY} > ./tests/include/zts/phpcpp/config.h
cd tests && ./test.sh -p "${PHP_BIN}"
diff --git a/common/extensionbase.h b/common/extensionbase.h
new file mode 100644
index 0000000..bf7f128
--- /dev/null
+++ b/common/extensionbase.h
@@ -0,0 +1,138 @@
+/**
+ * ExtensionBase.h
+ *
+ * Base class for ExtensionImpl objects. Common code used by both the Zend
+ * and HHVM engine.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013, 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ExtensionBase
+{
+protected:
+ /**
+ * Pointer to the extension object that is filled by the extension programmer
+ * @var Extension
+ */
+ Extension *_data;
+
+ /**
+ * Callback that is called after the engine is initialized and before the
+ * pageviews are going to be handled
+ * @var Callback
+ */
+ Callback _onStartup;
+
+ /**
+ * Callback that is called in front of each request
+ * @var Callback
+ */
+ Callback _onRequest;
+
+ /**
+ * Callback that is called right after each request
+ * @var Callback
+ */
+ Callback _onIdle;
+
+ /**
+ * Callback that is called right before the engine is closing down
+ * @var Callback
+ */
+ Callback _onShutdown;
+
+public:
+ /**
+ * Constructor
+ * @param data Extension object created by the extension programmer
+ */
+ ExtensionBase(Extension *data) : _data(data) {}
+
+ /**
+ * No copy'ing and no moving
+ */
+ ExtensionBase(const ExtensionImpl &extension) = delete;
+ ExtensionBase(ExtensionImpl &&extension) = delete;
+
+ /**
+ * Destructor
+ */
+ virtual ~ExtensionBase() {}
+
+ /**
+ * Register a function to be called when the PHP engine is ready
+ *
+ * The callback will be called after all extensions are loaded, and all
+ * functions and classes are available, but before the first pageview/request
+ * is handled. You can register this callback if you want to be notified
+ * when the engine is ready, for example to initialize certain things.
+ *
+ * @param callback
+ */
+ void onStartup(const Callback &callback)
+ {
+ // copy callback
+ _onStartup = callback;
+ }
+
+ /**
+ * Register a function to be called when the PHP engine is going to stop
+ *
+ * The callback will be called right before the process is going to stop.
+ * You can register a function if you want to clean up certain things.
+ *
+ * @param callback
+ */
+ void onShutdown(const Callback &callback)
+ {
+ // copy callback
+ _onShutdown = callback;
+ }
+
+ /**
+ * Register a callback that is called at the beginning of each pageview/request
+ *
+ * You can register a callback if you want to initialize certain things
+ * at the beginning of each request. Remember that the extension can handle
+ * multiple requests after each other, and you may want to set back certain
+ * global variables to their initial variables in front of each request
+ *
+ * @param callback
+ */
+ void onRequest(const Callback &callback)
+ {
+ // copy callback
+ _onRequest = callback;
+ }
+
+ /**
+ * Register a callback that is called to cleanup things after a pageview/request
+ *
+ * The callback will be called after _each_ request, so that you can clean up
+ * certain things and make your extension ready to handle the next request.
+ * This method is called onIdle because the extension is idle in between
+ * requests.
+ *
+ * @param callback
+ */
+ void onIdle(const Callback &callback)
+ {
+ // copy callback
+ _onIdle = callback;
+ }
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/common/includes.h b/common/includes.h
new file mode 100644
index 0000000..db29f10
--- /dev/null
+++ b/common/includes.h
@@ -0,0 +1,23 @@
+/**
+ * Includes.h
+ *
+ * All includes for compiling the common module files of PHP-CPP library
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Standard C and C++ libraries
+ */
+#include <sstream>
+
+/**
+ * Public include files
+ */
+#include "../include/modifiers.h"
+
+/**
+ * Generic implementation header files
+ */
+#include "streambuf.h"
diff --git a/src/modifiers.cpp b/common/modifiers.cpp
index 3720730..3720730 100644
--- a/src/modifiers.cpp
+++ b/common/modifiers.cpp
diff --git a/src/streambuf.cpp b/common/streambuf.cpp
index e258b4e..2d87f9a 100644
--- a/src/streambuf.cpp
+++ b/common/streambuf.cpp
@@ -54,39 +54,6 @@ int StreamBuf::overflow(int c)
}
/**
- * Called when the internal buffer should be synchronized
- * @return int
- */
-int StreamBuf::sync()
-{
- // current buffer size
- size_t size = pptr() - pbase();
-
- // is this the error stream or the regular output stream?
- if (_error)
- {
- // write to error (the zend_error() method is a varargs function,
- // which means that we have to include a printf() like format as first
- // parameter. We can not specify pbase() directly, because (1) it is
- // not null terminated and (2) it could contain % signs and allow all
- // sorts of buffer overflows.
- zend_error(_error, "%.*s", (int)size, pbase());
-
- }
- else
- {
- // write to zend
- zend_write(pbase(), size);
- }
-
- // reset the buffer
- pbump(-size);
-
- // done
- return 0;
-}
-
-/**
* End namespace
*/
}
diff --git a/src/streambuf.h b/common/streambuf.h
index ed1506a..ed1506a 100644
--- a/src/streambuf.h
+++ b/common/streambuf.h
diff --git a/config/config.cpp b/config/config.cpp
deleted file mode 100644
index 2fcd5ad..0000000
--- a/config/config.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * Config.cpp
- *
- * Simple programs that creates the config file for PHP-CPP. PHP-CPP needs
- * a different config file when it is installed on a system with multi-threaded
- * PHP, and on a system with single threaded PHP.
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2014 Copernica BV
- */
-#include <iostream>
-#include <php_config.h>
-
-/**
- * Main procedure
- * @return int
- */
-int main()
-{
-#ifdef ZTS
- // also define ZTS in the config file
- std::cout << "#define ZTS" << std::endl;
-#endif
-
- // done
- return 0;
-}
-
diff --git a/documentation/ten-reasons-for-using-php-cpp.html b/documentation/ten-reasons-for-using-php-cpp.html
index 7597fb2..d4a202b 100644
--- a/documentation/ten-reasons-for-using-php-cpp.html
+++ b/documentation/ten-reasons-for-using-php-cpp.html
@@ -1,6 +1,6 @@
<h1>Ten reasons for using PHP-CPP</h1>
<p>
- There are many reasons for using PHP-CPP. Let's name a view.
+ There are many reasons for using PHP-CPP. Let's name a few.
</p>
<h4>1. It's fast</h4>
<p>
@@ -41,7 +41,7 @@
<p>
Many programmers find it a matter of honor to make code that
can only be understood by themselves. We do not agree. The PHP-CPP library is
- fully documented (the documentation can be found on <a href="documentation">
+ fully documented (the documentation can be found on <a href="http://www.php-cpp.com/documentation">
www.php-cpp.com/documentation</a>), and the source code is full with
comments and explanations.
</p>
diff --git a/hhvm/extension.cpp b/hhvm/extension.cpp
new file mode 100644
index 0000000..9685b32
--- /dev/null
+++ b/hhvm/extension.cpp
@@ -0,0 +1,103 @@
+/**
+ * Extension.cpp
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013, 2014 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Constructor that defines a number of functions right away
+ * @param name Extension name
+ * @param version Extension version string
+ */
+Extension::Extension(const char *name, const char *version) :
+ Namespace(""), _impl(new ExtensionImpl(this, name, version)) {}
+
+/**
+ * Destructor
+ */
+Extension::~Extension()
+{
+ // get rid of the implementation object
+ delete _impl;
+}
+
+/**
+ * Register a function to be called when the PHP engine is ready
+ * @param callback
+ * @return Extension
+ */
+Extension &Extension::onStartup(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onStartup(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a function to be called when the PHP engine is going to stop
+ * @param callback
+ * @return Extension
+ */
+Extension &Extension::onShutdown(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onShutdown(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a callback that is called at the beginning of each pageview/request
+ * @param callback
+ */
+Extension &Extension::onRequest(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onRequest(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a callback that is called to cleanup things after a pageview/request
+ * @param callback
+ */
+Extension &Extension::onIdle(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onIdle(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Retrieve the module pointer
+ *
+ * This is the memory address that should be exported by the get_module()
+ * function.
+ *
+ * @return void*
+ */
+void *Extension::module()
+{
+ // pass on to the implementation
+ return _impl->module();
+}
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/hhvm/extensionimpl.h b/hhvm/extensionimpl.h
new file mode 100644
index 0000000..deb80a6
--- /dev/null
+++ b/hhvm/extensionimpl.h
@@ -0,0 +1,55 @@
+/**
+ * ExtensionImpl.h
+ *
+ * Implementation of the extension object for the HHVM engine
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ExtensionImpl : public ExtensionBase
+{
+private:
+ /**
+ * Pointer to the extension object that is filled by the extension programmer
+ * @var Extension
+ */
+ Extension *_data;
+
+public:
+ /**
+ * Constructor
+ * @param data Pointer to the extension object created by the extension programmer
+ * @param name Name of the extension
+ * @param version Version identifier of the extension
+ */
+ ExtensionImpl(Extension *data, const char *name, const char *version) : ExtensionBase(data) {}
+
+ /**
+ * Destructor
+ */
+ virtual ~ExtensionImpl() {}
+
+ /**
+ * Pointer to the module that is loaded by HHVM
+ * @return void*
+ */
+ void *module()
+ {
+ return nullptr;
+ }
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/hhvm/includes.h b/hhvm/includes.h
new file mode 100644
index 0000000..0e587db
--- /dev/null
+++ b/hhvm/includes.h
@@ -0,0 +1,55 @@
+/**
+ * Includes.h
+ *
+ * All includes for compiling the HHVM implementation of PHP-CPP
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Standard C and C++ libraries
+ */
+#include <functional>
+#include <list>
+#include <memory>
+#include <vector>
+#include <map>
+#include <string.h>
+#include <iostream>
+
+/**
+ * HHVM includes
+ */
+
+
+/**
+ * Public include files
+ */
+#include "../include/type.h"
+#include "../include/hashparent.h"
+#include "../include/value.h"
+#include "../include/parameters.h"
+#include "../include/classtype.h"
+#include "../include/argument.h"
+#include "../include/modifiers.h"
+#include "../include/classbase.h"
+#include "../include/interface.h"
+#include "../include/iterator.h"
+#include "../include/traversable.h"
+#include "../include/serializable.h"
+#include "../include/class.h"
+#include "../include/namespace.h"
+#include "../include/extension.h"
+
+/**
+ * Generic implementation header files
+ */
+#include "../common/extensionbase.h"
+#include "../common/streambuf.h"
+
+/**
+ * Specific HHVM header files for the implementation only
+ */
+#include "extensionimpl.h"
+
diff --git a/hhvm/streambuf.cpp b/hhvm/streambuf.cpp
new file mode 100644
index 0000000..805fc0f
--- /dev/null
+++ b/hhvm/streambuf.cpp
@@ -0,0 +1,59 @@
+/**
+ * StreamBuf.cpp
+ *
+ * Implementation file for the StreamBuf class
+ *
+ * @see http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Called when the internal buffer should be synchronized
+ * @return int
+ */
+int StreamBuf::sync()
+{
+ // current buffer size
+ size_t size = pptr() - pbase();
+
+ // is this the error stream or the regular output stream?
+ if (_error)
+ {
+ // write to error (the zend_error() method is a varargs function,
+ // which means that we have to include a printf() like format as first
+ // parameter. We can not specify pbase() directly, because (1) it is
+ // not null terminated and (2) it could contain % signs and allow all
+ // sorts of buffer overflows.
+
+ // @todo hhvm implementation
+
+// zend_error(_error, "%.*s", (int)size, pbase());
+
+ }
+ else
+ {
+ // @todo hhvm implementation
+
+ // write to zend
+// zend_write(pbase(), size);
+ }
+
+ // reset the buffer
+ pbump(-size);
+
+ // done
+ return 0;
+}
+
+/**
+ * End namespace
+ */
+}
diff --git a/hhvm/streams.cpp b/hhvm/streams.cpp
new file mode 100644
index 0000000..de327e2
--- /dev/null
+++ b/hhvm/streams.cpp
@@ -0,0 +1,41 @@
+/**
+ * Streams.cpp
+ *
+ * Implementation of the streams
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Some static buffers for writing data
+ * @var StreamBuf
+ */
+// @todo find the right constants
+static StreamBuf bufOut (0);
+static StreamBuf bufError (0); //E_ERROR);
+static StreamBuf bufWarning (0); //E_WARNING);
+static StreamBuf bufNotice (0); //E_NOTICE);
+static StreamBuf bufDeprecated (0); //E_DEPRECATED);
+
+/**
+ * Create the actual steams
+ * @var std::ostream
+ */
+std::ostream out (&bufOut);
+std::ostream error (&bufError);
+std::ostream warning (&bufWarning);
+std::ostream notice (&bufNotice);
+std::ostream deprecated (&bufDeprecated);
+
+/**
+ * End namespace
+ */
+}
+
diff --git a/include/argument.h b/include/argument.h
index 68ac7df..81b1bf4 100644
--- a/include/argument.h
+++ b/include/argument.h
@@ -8,15 +8,10 @@
* classes instead.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
+ * @copyright 2013, 2014 Copernica BV
*/
/**
- * Forward declaration
- */
-struct _zend_arg_info;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -28,21 +23,9 @@ class Argument
{
public:
/**
- * Copy constructor
- * @param argument
- */
- Argument(const Argument &argument);
-
- /**
- * Move constructor
- * @param argument
- */
- Argument(Argument &&argument);
-
- /**
* Destructor
*/
- virtual ~Argument();
+ virtual ~Argument() {}
protected:
/**
@@ -52,7 +35,8 @@ protected:
* @param required Is this argument required?
* @param byref Is this a reference argument
*/
- Argument(const char *name, Type type, bool required = true, bool byref = false);
+ Argument(const char *name, Type type, bool required = true, bool byref = false) :
+ _name(name), _type(type), _required(required), _byReference(byref) {}
/**
* Constructor
@@ -62,17 +46,11 @@ protected:
* @param required Is this argument required?
* @param byref Is this a reference argument?
*/
- Argument(const char *name, const char *classname, bool nullable = true, bool required = true, bool byref = false);
+ Argument(const char *name, const char *classname, bool nullable = true, bool required = true, bool byref = false) :
+ _name(name), _type(Type::Object), _classname(classname), _nullable(nullable), _required(required), _byReference(byref) {}
public:
/**
- * Fill an arg_info structure with data
- * @param info
- * @internal
- */
- void fill(struct _zend_arg_info *info) const;
-
- /**
* Is this a required argument?
* @return bool
* @internal
@@ -81,19 +59,88 @@ public:
{
return _required;
}
-
+
+ /**
+ * Name of the argument
+ * @return std::string
+ */
+ const std::string &name() const
+ {
+ return _name;
+ }
+
+ /**
+ * Type-hint for the argument
+ * @return Type
+ */
+ Type type() const
+ {
+ return _type;
+ }
+
+ /**
+ * If the type is a class, the name of the class
+ * @return std::string
+ */
+ const std::string &classname() const
+ {
+ return _classname;
+ }
+
+ /**
+ * Is it allowed to pass parameter with a null value?
+ * @return bool
+ */
+ bool allowNull() const
+ {
+ return _nullable;
+ }
+
+ /**
+ * Is this a parameter-by-reference?
+ * @return bool
+ */
+ bool byReference() const
+ {
+ return _byReference;
+ }
+
private:
/**
- * The argument info
- * @var zend_arg_info
+ * Name of the argument
+ * @var std::string
*/
- struct _zend_arg_info *_info;
+ std::string _name;
/**
+ * Type of argument
+ * @var Type
+ */
+ Type _type;
+
+ /**
+ * Classname, if this is a parameter that is supposed to be an instance of a class
+ * @var std::string
+ */
+ std::string _classname;
+
+ /**
+ * May the parameter be null?
+ * @var bool
+ */
+ bool _nullable;
+
+ /**
* Is this a required argument
* @var bool
*/
bool _required;
+
+ /**
+ * Is this a 'by-reference' parameter?
+ * @var bool
+ */
+ bool _byReference;
};
/**
diff --git a/include/array.h b/include/array.h
index 26fec24..0b6ceb9 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("Assiging a non-array to an array variable");
+ if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to an array variable");
}
/**
@@ -93,7 +93,7 @@ public:
if (this == &value) return *this;
// type must be valid
- if (value.type() != Type::Array) throw Php::Exception("Assiging a non-array to a fixed array variable");
+ if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to a fixed array variable");
// call base
Value::operator=(value);
diff --git a/include/base.h b/include/base.h
index 8b3e561..87c7483 100644
--- a/include/base.h
+++ b/include/base.h
@@ -13,13 +13,21 @@ namespace Php {
/**
* Forward declarations
*/
-struct MixedObject;
+class ObjectImpl;
+
/**
* Class definition
*/
class Base
{
+private:
+ /**
+ * Object handle in the PHP engine
+ * @var ObjectImpl
+ */
+ ObjectImpl *_impl = nullptr;
+
protected:
/**
* Constructor
@@ -241,41 +249,25 @@ public:
*/
int __compare(const Base &base) const;
-
-private:
- /**
- * Store the object in the zend object cache
- * @param entry
- * @param tsrm_ls
- * @return MixedObject
- */
- MixedObject *store(struct _zend_class_entry *entry TSRMLS_DC);
+private:
/**
- * Retrieve the handle
- * @return int
+ * Get access to the implementation object
+ * @return ObjectImpl
*/
- int handle() const
+ const ObjectImpl *implementation() const
{
- return _handle;
+ return _impl;
}
-
- /**
- * The handle in the zend object cache
- * @var int
- */
- int _handle = 0;
/**
- * Friends that have access to the private members
+ * Classes that have direct access to private date
*/
- friend class Value;
+ friend class ObjectImpl;
friend class Object;
- friend class ClassImpl;
-
+ friend class Value;
};
-
/**
* End of namespace
*/
diff --git a/include/class.h b/include/class.h
index 7b9a928..e0316df 100644
--- a/include/class.h
+++ b/include/class.h
@@ -16,11 +16,6 @@
*/
/**
- * Zend/SPL interfaces that we support
- */
-extern struct _zend_class_entry *zend_ce_arrayaccess;
-
-/**
* Set up namespace
*/
namespace Php {
diff --git a/include/exception.h b/include/exception.h
index dd38035..671df9e 100644
--- a/include/exception.h
+++ b/include/exception.h
@@ -30,42 +30,51 @@ private:
*/
int _code;
+ /**
+ * Has this exception been processed by native C++ code?
+ * @var bool
+ */
+ bool _processed = false;
+
public:
/**
* Constructor
* @param &string
*/
- Exception(const std::string &message, int code = 0) : std::exception(), _message(message), _code(code)
- {
- }
+ Exception(const std::string &message, int code = 0) : std::exception(), _message(message), _code(code) {}
/**
* Destructor
*/
- virtual ~Exception() throw()
+ virtual ~Exception() throw() {}
+
+ /**
+ * Overridden what method
+ * @return const char *
+ */
+ virtual const char *what() const noexcept override
{
+ return _message.c_str();
}
/**
* Returns the message of the exception.
* @return &string
*/
- std::string &message() throw()
+ const std::string &message() const throw()
{
return _message;
}
/**
- * Process the exception
- *
- * This method is called only from within the PHP-CPP library,
- * and will turn the exception into a PHP exception
- *
- * @param tsrm_ls
- *
- * @internal
+ * Is this a native exception (one that was thrown from C++ code)
+ * @return bool
*/
- virtual void process(TSRMLS_D);
+ virtual bool native() const
+ {
+ // yes, it is native
+ return true;
+ }
};
/**
diff --git a/include/extension.h b/include/extension.h
index 6d1fa0c..fcc0f72 100644
--- a/include/extension.h
+++ b/include/extension.h
@@ -6,7 +6,7 @@
* apache process starts - and will be used for all subsequent requests that
* are handled by Apache.
*
- * For some environments (for example CLI scripts and FastCGI calls) only one
+ * For some environments (for example CLI scripts and CGI calls) only one
* request is handled by an extension instance, but for others (when PHP runs
* as module in a webserver) many requests are handled by the same extension
* instance.
@@ -16,11 +16,6 @@
*/
/**
- * Structures referenced in this class
- */
-struct _zend_module_entry;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -28,7 +23,7 @@ namespace Php {
/**
* Forward declaration
*/
-class Extension;
+class ExtensionImpl;
/**
* Signature of a callback
@@ -46,7 +41,7 @@ public:
* @param name Extension name
* @param version Extension version string
*/
- Extension(const char *name = NULL, const char *version = NULL);
+ Extension(const char *name, const char *version = "1.0");
/**
* No copy'ing and no moving
@@ -67,13 +62,10 @@ public:
* is handled. You can register this callback if you want to be notified
* when the engine is ready, for example to initialize certain things.
*
- * @param callback
+ * @param callback Function to be called
+ * @return Extension Same object to allow chaining
*/
- void onStartup(const Callback &callback)
- {
- // copy callback
- _onStartup = callback;
- }
+ Extension &onStartup(const Callback &callback);
/**
* Register a function to be called when the PHP engine is going to stop
@@ -81,13 +73,10 @@ public:
* The callback will be called right before the process is going to stop.
* You can register a function if you want to clean up certain things.
*
- * @param callback
+ * @param callback Function to be called
+ * @return Extension Same object to allow chaining
*/
- void onShutdown(const Callback &callback)
- {
- // copy callback
- _onShutdown = callback;
- }
+ Extension &onShutdown(const Callback &callback);
/**
* Register a callback that is called at the beginning of each pageview/request
@@ -97,13 +86,10 @@ public:
* multiple requests after each other, and you may want to set back certain
* global variables to their initial variables in front of each request
*
- * @param callback
+ * @param callback Function to be called
+ * @return Extension Same object to allow chaining
*/
- void onRequest(const Callback &callback)
- {
- // copy callback
- _onRequest = callback;
- }
+ Extension &onRequest(const Callback &callback);
/**
* Register a callback that is called to cleanup things after a pageview/request
@@ -113,105 +99,38 @@ public:
* This method is called onIdle because the extension is idle in between
* requests.
*
- * @param callback
+ * @param callback Function to be called
+ * @return Extension Same object to allow chaining
*/
- void onIdle(const Callback &callback)
- {
- // copy callback
- _onIdle = callback;
- }
+ Extension &onIdle(const Callback &callback);
/**
- * Retrieve the module entry
+ * Retrieve the module pointer
*
* This is the memory address that should be exported by the get_module()
* function.
*
- * @return _zend_module_entry
+ * @return void*
*/
- _zend_module_entry *module();
+ void *module();
/**
* Cast to a module entry
- * @return _zend_module_entry*
+ *
+ * @return void*
*/
- operator _zend_module_entry * ()
+ operator void * ()
{
return module();
}
private:
/**
- * The information that is passed to the Zend engine
- *
- * Although it would be slightly faster to not make this a pointer, this
- * would require that client code also includes the PHP header files, which
- * we try to prevent with the PHP-CPP library, so we allocate it dynamically.
+ * The implementation object
*
- * @var zend_module_entry
- */
- _zend_module_entry *_entry;
-
- /**
- * Callback that is called after the engine is initialized and before the
- * pageviews are going to be handled
- * @var Callback
- */
- Callback _onStartup;
-
- /**
- * Callback that is called in front of each request
- * @var Callback
- */
- Callback _onRequest;
-
- /**
- * Callback that is called right after each request
- * @var Callback
- */
- Callback _onIdle;
-
- /**
- * Callback that is called right before the engine is closing down
- * @var Callback
- */
- Callback _onShutdown;
-
- /**
- * Function that is called when the extension initializes
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
- */
- static int onStartup(int type, int module_number TSRMLS_DC);
-
- /**
- * Function that is called when the extension is about to be stopped
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int
- */
- static int onShutdown(int type, int module_number TSRMLS_DC);
-
- /**
- * Function that is called when a request starts
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
- */
- static int onRequest(int type, int module_number TSRMLS_DC);
-
- /**
- * Function that is called when a request is ended
- * @param type Module type
- * @param number Module number
- * @param tsrm_ls
- * @return int 0 on success
+ * @var ExtensionImpl
*/
- static int onIdle(int type, int module_number TSRMLS_DC);
+ ExtensionImpl *_impl;
};
/**
diff --git a/include/iterator.h b/include/iterator.h
index 13b30fc..331c8b3 100644
--- a/include/iterator.h
+++ b/include/iterator.h
@@ -2,19 +2,19 @@
* Iterator.h
*
* Base class for iterators. Extension writers that want to create traversable
- * classes, should override this class and implement all pure virtual methods
- * in it.
+ * classes, should override the Php::Traversable base class. This base class
+ * forces you to implement a getIterator() method that returns an instance of
+ * a Php::Iterator class.
+ *
+ * In this file you find the signature of the Php::Iterator class. It mostly has
+ * pure virtual methods, which means that you should create a derived class
+ * that implements all these methods.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
*/
/**
- * Forward declarations
- */
-struct _zend_object_iterator_funcs;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -64,7 +64,7 @@ public:
*/
virtual void rewind() = 0;
-private:
+protected:
/**
* During the lifetime of the iterator, the object over which
* it iterates is keps as a private variable. This ensures that
@@ -73,92 +73,6 @@ private:
*/
Value _object;
- /**
- * The current() method that is called by the Zend engine wants a
- * pointer-to-pointer-to-a-zval. Because of this, we have to keep the
- * current value in memory after the current() method returns because
- * the pointer would otherwise fall out of scope. This is (once again)
- * odd behavior of the Zend engine, but we'll have to live with that
- * @var Value
- */
- Value _current;
-
- /**
- * Internal method that returns the implementation object
- * @return zend_object_iterator
- */
- struct _zend_object_iterator *implementation();
-
- /**
- * Iterator destructor method
- * @param iter
- * @param tsrm_ls
- */
- static void destructor(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Iterator valid function
- * Returns FAILURE or SUCCESS
- * @param iter
- * @param tsrm_ls
- * @return int
- */
- static int valid(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Fetch the current item
- * @param iter
- * @param data
- * @param tsrm_ls
- */
- static void current(struct _zend_object_iterator *iter, struct _zval_struct ***data TSRMLS_DC);
-
- /**
- * Fetch the key for the current element (optional, may be NULL). The key
- * should be written into the provided zval* using the ZVAL_* macros. If
- * this handler is not provided auto-incrementing integer keys will be
- * used.
- * @param iter
- * @param data
- * @param tsrm_ls
- */
- static void key(struct _zend_object_iterator *iter, struct _zval_struct *data TSRMLS_DC);
-
- /**
- * Function to retrieve the current key, php 5.3 style
- * @param iter
- * @param str_key
- * @param str_key_len
- * @param int_key
- * @param tsrm_ls
- * @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
- */
- static int key(struct _zend_object_iterator *iter, char **str_key, unsigned int *str_key_len, unsigned long *int_key TSRMLS_DC);
-
- /**
- * Step forwards to the next element
- * @param iter
- * @param tsrm_ls
- */
- static void next(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Rewind the iterator back to the start
- * @param iter
- * @param tsrm_ls
- */
- static void rewind(struct _zend_object_iterator *iter TSRMLS_DC);
-
- /**
- * Get access to all iterator functions
- * @return zend_object_iterator_funcs
- */
- static struct _zend_object_iterator_funcs *functions();
-
- /**
- * Classbase is a friend
- */
- friend class ClassImpl;
};
/**
diff --git a/include/namespace.h b/include/namespace.h
index 5830339..25d4e5e 100644
--- a/include/namespace.h
+++ b/include/namespace.h
@@ -23,32 +23,43 @@ class Function;
*/
class Namespace
{
-public:
+protected:
/**
- * Constructor
- * @param name Name of the namespace
+ * Name of the namespace
+ * @var string
*/
- Namespace(const char *name) : _name(name) {}
+ std::string _name;
+
+ /**
+ * Functions defined in the namespace
+ * @var list
+ */
+ std::list<std::shared_ptr<Function>> _functions;
+
+ /**
+ * Classes defined in the namespace
+ * @var list
+ */
+ std::list<std::shared_ptr<ClassBase>> _classes;
/**
- * Copy constructor
- * @param ns Namespace to copy
+ * Namespaces defined inside the namespace
+ * @var list
*/
- Namespace(const Namespace &ns) :
- _name(ns._name),
- _functions(ns._functions),
- _classes(ns._classes),
- _namespaces(ns._namespaces) {}
-
+ std::list<std::shared_ptr<Namespace>> _namespaces;
+
/**
- * Move constructor
- * @param ns
+ * Ini entry defined by the extension
+ * @var list
*/
- Namespace(Namespace &&ns) :
- _name(std::move(ns._name)),
- _functions(std::move(ns._functions)),
- _classes(std::move(ns._classes)),
- _namespaces(std::move(ns._namespaces)) {}
+ std::list<std::shared_ptr<Ini>> _ini_entries;
+
+public:
+ /**
+ * Constructor
+ * @param name Name of the namespace
+ */
+ Namespace(const char *name) : _name(name) {}
/**
* Destructor
@@ -56,7 +67,7 @@ public:
virtual ~Namespace() {}
/**
- * Add a native function directly to the extension
+ * Add a native function directly to the namespace
* @param name Name of the function
* @param function The function to add
* @param arguments Optional argument specification
@@ -68,106 +79,91 @@ public:
Namespace &add(const char *name, const native_callback_3 &function, const Arguments &arguments = {});
/**
- * Add a native class to the extension by moving it
+ * Add a native class to the namespace by moving it
* @param type The class implementation
* @return Namespace Same object to allow chaining
*/
template<typename T>
Namespace &add(Class<T> &&type)
{
- // make a copy of the object
- auto *copy = new Class<T>(std::move(type));
-
- // and add it to the list of classes
- _classes.push_back(std::unique_ptr<ClassBase>(copy));
+ // make a copy of the object, and add it to the list of classes
+ _classes.push_back(std::unique_ptr<ClassBase>(new Class<T>(std::move(type))));
// allow chaining
return *this;
}
/**
- * Add a native class to the extension by copying it
+ * Add a native class to the namespace by copying it
* @param type The class implementation
- * @param Namespace Same object to allow chaining
+ * @return Namespace Same object to allow chaining
*/
template<typename T>
Namespace &add(const Class<T> &type)
{
- // make a copy of the object
- auto *copy = new Class<T>(std::move(type));
-
// and add it to the list of classes
- _classes.push_back(std::unique_ptr<ClassBase>(copy));
+ _classes.push_back(std::unique_ptr<ClassBase>(new Class<T>(type)));
// allow chaining
return *this;
}
/**
- * Add an interface to the extension by moving it
+ * Add an interface to the namespace by moving it
* @param interface The interface properties
+ * @return Namespace Same object to allow chaining
*/
Namespace &add(Interface &&interface)
{
- // make a copy of the object
- auto *copy = new Interface(std::move(interface));
-
- // and add it to the list of classes
- _classes.push_back(std::unique_ptr<ClassBase>(copy));
+ // make a copy and add it to the list of classes
+ _classes.push_back(std::unique_ptr<ClassBase>(new Interface(std::move(interface))));
// allow chaining
return *this;
}
/**
- * Add an interface to the extension by copying it
+ * Add an interface to the namespace by copying it
* @param interface The interface properties
+ * @return Namespace Same object to allow chaining
*/
Namespace &add(const Interface &interface)
{
- // make a copy of the object
- auto *copy = new Interface(interface);
-
- // and add it to the list of classes
- _classes.push_back(std::unique_ptr<ClassBase>(copy));
+ // make a copy and add it to the list of classes
+ _classes.push_back(std::unique_ptr<ClassBase>(new Interface(interface)));
// allow chaining
return *this;
}
/**
- * Add a namespace to the extension by moving it
+ * Add a namespace to the namespace by moving it
* @param ns The namespace
+ * @return Namespace Same object to allow chaining
*/
Namespace &add(Namespace &&ns)
{
- // make a copy of the object
- auto *copy = new Namespace(std::move(ns));
-
// add it to the list of namespaces
- _namespaces.push_back(std::unique_ptr<Namespace>(copy));
+ _namespaces.push_back(std::unique_ptr<Namespace>(new Namespace(std::move(ns))));
// allow chaining
return *this;
}
/**
- * Add a namespace to the extension by copying it
+ * Add a namespace to the namespace by copying it
* @param ns The namespace
+ * @return Namespace Same object to allow chaining
*/
Namespace &add(const Namespace &ns)
{
- // make a copy of the object
- auto *copy = new Namespace(std::move(ns));
-
- // add it to the list of namespaces
- _namespaces.push_back(std::unique_ptr<Namespace>(copy));
+ // make a copy and add it to the list of namespaces
+ _namespaces.push_back(std::unique_ptr<Namespace>(new Namespace(ns)));
// allow chaining
return *this;
}
-
/**
* Add a ini entry to the extension by moving it
* @param ini The class implementation
@@ -175,11 +171,8 @@ public:
*/
Namespace &add(Ini &&ini)
{
- // make a copy of the object
- auto *copy = new Ini(std::move(ini));
-
// and add it to the list of classes
- _ini_entries.push_back(std::unique_ptr<Ini>(copy));
+ _ini_entries.push_back(std::unique_ptr<Ini>(new Ini(std::move(ini))));
// allow chaining
return *this;
@@ -192,48 +185,13 @@ public:
*/
Namespace &add(const Ini &ini)
{
- // make a copy of the object
- auto *copy = new Ini(std::move(ini));
-
// and add it to the list of classes
- _ini_entries.push_back(std::unique_ptr<Ini>(copy));
+ _ini_entries.push_back(std::unique_ptr<Ini>(new Ini(ini)));
// allow chaining
return *this;
}
-
-protected:
- /**
- * Name of the namespace
- * @var string
- */
- std::string _name;
-
- /**
- * Functions defined by the extension
- * @var list
- */
- std::list<std::shared_ptr<Function>> _functions;
-
- /**
- * Classes defined by the extension
- * @var list
- */
- std::list<std::shared_ptr<ClassBase>> _classes;
-
- /**
- * Namespaces defined by the extension
- * @var list
- */
- std::list<std::shared_ptr<Namespace>> _namespaces;
-
- /**
- * Ini entry defined by the extension
- * @var list
- */
- std::list<std::shared_ptr<Ini>> _ini_entries;
-
/**
* The total number of functions
* @return size_t
@@ -249,21 +207,27 @@ protected:
// done
return result;
}
-
+
/**
- * Initialize all functions in this namespace
- * @param ns Namespace prefix
- * @param entries The array to be filled
- * @return int Number of functions that were initialized
+ * Apply a callback to each registered function
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered function.
+ *
+ * @param callback
*/
- size_t initialize(const std::string &ns, struct _zend_function_entry entries[]);
-
+ void apply(const std::function<void(const std::string &ns, Function &func)> &callback);
+
/**
- * Initialize the namespace after it was registered
- * @param parent Parent namespace
- * @param tsrm_ls
+ * Apply a callback to each registered class
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered class.
+ *
+ * @param callback
*/
- void initialize(const std::string &parent TSRMLS_DC);
+ void apply(const std::function<void(const std::string &ns, ClassBase &clss)> &callback);
+
};
/**
diff --git a/include/object.h b/include/object.h
index 1445943..97c9482 100644
--- a/include/object.h
+++ b/include/object.h
@@ -140,7 +140,7 @@ public:
if (this == &value) return *this;
// type must be valid
- if (value.type() != Type::Object) throw Php::Exception("Assiging a non-object to an object variable");
+ if (value.type() != Type::Object) throw Php::Exception("Assigning a non-object to an object variable");
// call base
Value::operator=(value);
diff --git a/include/parameters.h b/include/parameters.h
index fa53004..b464260 100644
--- a/include/parameters.h
+++ b/include/parameters.h
@@ -22,15 +22,25 @@ class Base;
*/
class Parameters : public std::vector<Value>
{
-public:
+private:
/**
- * Constructor
- * @param this_ptr Optional this_ptr
- * @param argc Number of arguments
- * @param tsrm_ls
+ * The base object
+ * @var Base
*/
- Parameters(struct _zval_struct *this_ptr, int argc TSRMLS_DC);
+ Base *_object = nullptr;
+protected:
+ /**
+ * Protected constructor
+ *
+ * The constructor is protected because extension programmers are not
+ * supposed to instantiate parameters objects themselves
+ *
+ * @param object The 'this' object
+ */
+ Parameters(Base *object) : _object(object) {}
+
+public:
/**
* Destructor
*/
@@ -44,13 +54,6 @@ public:
{
return _object;
}
-
-private:
- /**
- * The base object
- * @var Base
- */
- Base *_object = nullptr;
};
/**
diff --git a/include/value.h b/include/value.h
index e7fa825..95985d7 100644
--- a/include/value.h
+++ b/include/value.h
@@ -943,12 +943,13 @@ protected:
friend class Globals;
friend class Member;
friend class ClassImpl;
- friend class Iterator;
+ friend class IteratorImpl;
friend class Extension;
friend class HashIterator;
friend class TraverseIterator;
friend class HashMember<int>;
friend class HashMember<std::string>;
+ friend class Callable;
};
/**
diff --git a/include/valueiterator.h b/include/valueiterator.h
index fd8118d..95cdac6 100644
--- a/include/valueiterator.h
+++ b/include/valueiterator.h
@@ -12,12 +12,6 @@
*/
/**
- * Forward declaration
- */
-struct _hashtable;
-struct bucket;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -25,7 +19,7 @@ namespace Php {
/**
* Forward declarations
*/
-class IteratorImpl;
+class ValueIteratorImpl;
/**
* Class definition
@@ -37,7 +31,7 @@ public:
* Constructor
* @param impl Implementation iterator
*/
- ValueIterator(IteratorImpl *impl) : _impl(impl) {}
+ ValueIterator(ValueIteratorImpl *impl) : _impl(impl) {}
/**
* Copy constructor
@@ -125,7 +119,7 @@ private:
* Pointer to the actual implementation
* @var std::unique_ptr
*/
- IteratorImpl *_impl;
+ ValueIteratorImpl *_impl;
};
diff --git a/phpcpp.h b/phpcpp.h
index 4e2ea76..ce1beb5 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -23,32 +23,6 @@
#include <map>
/**
- * Include PHP config
- */
-#include <phpcpp/config.h>
-
-/**
- * Is ZTS enabled?
- */
-#ifdef ZTS
-
- // enable TSRM
-# define TSRMLS_C tsrm_ls
-# define TSRMLS_CC ,tsrm_ls
-# define TSRMLS_D void ***tsrm_ls
-# define TSRMLS_DC ,void ***tsrm_ls
-
-#else
-
- // disable TSRM
-# define TSRMLS_C
-# define TSRMLS_CC
-# define TSRMLS_D
-# define TSRMLS_DC
-
-#endif
-
-/**
* Include all headers files that are related to this library
*/
#include <phpcpp/ini.h>
diff --git a/src/argument.cpp b/src/argument.cpp
deleted file mode 100644
index a2aa8d5..0000000
--- a/src/argument.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Argument.cpp
- *
- * Implementation for the Argument class
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Constructor
- * @param name Name of the argument
- * @param type Argument type
- * @param required Is this argument required?
- * @param byref Is this a reference argument
- */
-Argument::Argument(const char *name, Type type, bool required, bool byref)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- _info->name = name;
- _info->name_len = strlen(name);
-
-#if PHP_VERSION_ID >= 50400
-
- // since php 5.4 there is a type-hint
- _info->type_hint = (unsigned char)(type == Type::Array || type == Type::Callable ? type : Type::Null);
-
-# if PHP_VERSION_ID >= 50600
-
- // from PHP 5.6 and onwards, an is_variadic property can be set, this
- // specifies whether this argument is the first argument that specifies
- // the type for a variable length list of arguments. For now we only
- // support methods and functions with a fixed number of arguments.
- _info->is_variadic = false;
-
-# endif
-
-#else
-
- // php 5.3 code
- _info->array_type_hint = type == Type::Array;
- _info->return_reference = false;
- _info->required_num_args = 0; // @todo is this correct?
-
-#endif
-
- // this parameter is a regular type
- _info->class_name = NULL;
- _info->class_name_len = 0;
- _info->allow_null = false;
- _info->pass_by_reference = byref;
-
- // store if required
- _required = required;
-}
-
-/**
- * Constructor
- * @param name Name of the argument
- * @param classname Name of the class
- * @param nullable Can it be null?
- * @param required Is this argument required?
- * @param byref Is this a reference argument?
- */
-Argument::Argument(const char *name, const char *classname, bool nullable, bool required, bool byref)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- _info->name = name;
- _info->name_len = strlen(name);
-
-#if PHP_VERSION_ID >= 50400
-
- // since php 5.4 there is a type hint
- _info->type_hint = (unsigned char)Type::Object;
-
-# if PHP_VERSION_ID >= 50600
-
- // from PHP 5.6 and onwards, an is_variadic property can be set, this
- // specifies whether this argument is the first argument that specifies
- // the type for a variable length list of arguments. For now we only
- // support methods and functions with a fixed number of arguments.
- _info->is_variadic = false;
-
-# endif
-
-#else
-
- // php 5.3 code
- _info->array_type_hint = false;
- _info->return_reference = false;
- _info->required_num_args = 0; // @todo is this correct?
-
-#endif
-
- // the parameter is a class
- _info->class_name = classname;
- _info->class_name_len = strlen(classname);
- _info->allow_null = nullable;
- _info->pass_by_reference = byref;
-
- // store if required
- _required = required;
-}
-
-/**
- * Copy constructor
- * @param argument
- */
-Argument::Argument(const Argument &argument)
-{
- // construct object
- _info = new zend_arg_info;
-
- // fill members
- *_info = *argument._info;
-
- // store if required
- _required = argument._required;
-}
-
-/**
- * Move constructor
- * @param argument
- */
-Argument::Argument(Argument &&argument)
-{
- // copy memory pointer
- _info = argument._info;
-
- // forget in other object
- argument._info = nullptr;
-
- // store if required
- _required = argument._required;
-}
-
-/**
- * Destructor
- */
-Argument::~Argument()
-{
- if (_info) delete _info;
-}
-
-/**
- * Fill an arg_info structure with data
- * @param info
- * @internal
- */
-void Argument::fill(struct _zend_arg_info *info) const
-{
- // copy all data
- *info = *_info;
-}
-
-/**
- * End of namespace
- */
-}
diff --git a/src/exception.cpp b/src/exception.cpp
deleted file mode 100644
index 810a73c..0000000
--- a/src/exception.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Exception.cpp
- *
- * Implementation for the exception class
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2014 Copernica BV
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Process the exception
- *
- * This method is called only from within the PHP-CPP library,
- * and will turn the exception into a PHP exception
- *
- * @param tsrm_ls
- */
-void Exception::process(TSRMLS_D)
-{
- // an exception originally thrown by C++ should be passed on to PHP
- zend_throw_exception(zend_exception_get_default(TSRMLS_C), (char*)message().c_str(), 0 TSRMLS_CC);
-}
-
-/**
- * End namespace
- */
-}
-
diff --git a/src/mixedobject.h b/src/mixedobject.h
deleted file mode 100644
index 4db74da..0000000
--- a/src/mixedobject.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * MixedObject.h
- *
- * Structure that combines a Zend object with an object in C++
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Structure that combines a C++ object with a zend object
- */
-struct MixedObject
-{
- /**
- * The actual object is the first member, so that casting
- * the MixedObject to a zend_object will also result in a valid pointer
- * @var zend_object
- */
- zend_object php;
-
- /**
- * Pointer to the C++ implementation
- * @var Base
- */
- Base *cpp;
-};
-
-/**
- * End of namespace
- */
-}
-
-
diff --git a/src/origexception.cpp b/src/origexception.cpp
deleted file mode 100644
index f64d696..0000000
--- a/src/origexception.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Implementation of the exception that was originally thrown by PHP
- * code or the zend engine, and that could or could not be picked
- * up by C++ code
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Destructor
- */
-OrigException::~OrigException() noexcept
-{
- // skip if the exception was restored
- if (_restored) return;
-
- // we need the tsrm_ls var
- TSRMLS_FETCH();
-
- // clean up the exception, because it was handled in C++ code
- zend_clear_exception(TSRMLS_C);
-}
-
-/**
- * End of namespace
- */
-}
-
diff --git a/src/origexception.h b/src/origexception.h
deleted file mode 100644
index 5cbb0e1..0000000
--- a/src/origexception.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * OrigException.h
- *
- * Class that wraps around an exception that was thrown by PHP code,
- * and that could - but not necessarily has to - be caught by C++
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Class definition
- */
-class OrigException : public Value, public Exception
-{
-private:
- /**
- * Has the exception been restored by the C++ code so that it can be dealt by PHP?
- * @var boolean
- */
- bool _restored = false;
-
-public:
- /**
- * Constructor
- * @param zval
- */
- OrigException(struct _zval_struct *zval) :
- Value(zval), Exception("OrigException") {}
-
- /**
- * Copy constructor
- * @param exception
- */
- OrigException(const OrigException &exception) :
- Value(exception), Exception("OrigException"), _restored(exception._restored) {}
-
- /**
- * Move constructor
- * @param exception
- */
- OrigException(OrigException &&exception) :
- Value(std::move(exception)), Exception("OrigException"), _restored(exception._restored)
- {
- // set other exception to restored so that it wont
- // do anything on destruction
- exception._restored = true;
- }
-
- /**
- * Destructor
- */
- virtual ~OrigException() throw();
-
- /**
- * Process the exception
- *
- * This will restore the exception so that it can be further processed
- * in PHP code
- *
- * @param tsrm_ls
- * @internal
- */
- virtual void process(TSRMLS_D) override
- {
- // mark exception as restored
- _restored = true;
- }
-};
-
-/**
- * End of namespace
- */
-}
diff --git a/src/parameters.cpp b/src/parameters.cpp
deleted file mode 100644
index c4ed9c7..0000000
--- a/src/parameters.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Parameters.cpp
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2013 Copernica BV
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Parameters
- * @param this_ptr Pointer to the object
- * @param argc Number of arguments
- * @param tsrm_ls
- */
-Parameters::Parameters(zval *this_ptr, int argc TSRMLS_DC)
-{
- // reserve plenty of space
- reserve(argc);
-
- // loop through the arguments
- for (int i=0; i<argc; i++)
- {
- // get the argument
- zval **arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (argc-i));
-
- // append value
- push_back(Value(*arg));
- }
-
- // skip if there is no this_ptr
- if (!this_ptr) return;
-
- // get the mixed object
- MixedObject *obj = (MixedObject *)zend_object_store_get_object(this_ptr TSRMLS_CC);
-
- // store the CPP object
- _object = obj->cpp;
-}
-
-/**
- * End of namespace
- */
-}
-
diff --git a/tests/php/phpt/variables/021-HashMember-3.phpt b/tests/php/phpt/variables/021-HashMember-3.phpt
index c6c517f..20f43ba 100644
--- a/tests/php/phpt/variables/021-HashMember-3.phpt
+++ b/tests/php/phpt/variables/021-HashMember-3.phpt
@@ -22,6 +22,5 @@ array (
'key1' =>
array (
'key2' => 'val1-2',
- 'key3' => 'val1-3',
),
) \ No newline at end of file
diff --git a/src/arithmetic.h b/zend/arithmetic.h
index 20e346e..20e346e 100644
--- a/src/arithmetic.h
+++ b/zend/arithmetic.h
diff --git a/src/base.cpp b/zend/base.cpp
index a828083..5d15011 100644
--- a/src/base.cpp
+++ b/zend/base.cpp
@@ -18,61 +18,61 @@ namespace Php {
* @param tsrm_ls
* @return MixedObject
*/
-MixedObject *Base::store(zend_class_entry *entry TSRMLS_DC)
-{
- // allocate memory for the object
- MixedObject *result = (MixedObject *)emalloc(sizeof(MixedObject));
-
- // store the new c++ object
- result->cpp = this;
-
- // store the class entry in the newly created object
- result->php.ce = entry;
-
- // initialize the object
- zend_object_std_init(&result->php, entry TSRMLS_CC);
-
-#if PHP_VERSION_ID < 50399
-
- // tmp variable
- zval *tmp;
-
- // initialize the properties, php 5.3 way
- zend_hash_copy(result->php.properties, &entry->default_properties, (copy_ctor_func_t) zval_property_ctor, &tmp, sizeof(zval*));
-
-#else
-
- // version higher than 5.3 have an easier way to initialize
- object_properties_init(&result->php, entry);
-
-#endif
-
-#ifdef ZTS
-
- // when in thread safety mode, the destruct method and free method have
- // an extra parameter holding thread information
- using DestructType = void(zend_object*,unsigned int,void***);
- using FreeType = void(zend_object*,void***);
-
-#else
-
- // not in thread mode: no special parameter for the tsrm_ls variable
- using DestructType = void(zend_object*,unsigned int);
- using FreeType = void(zend_object*);
-
-#endif
-
- // store the two destruct methods in temporary vars
- DestructType *destructMethod = &ClassImpl::destructObject;
- FreeType *freeMethod = &ClassImpl::freeObject;
-
- // the destructor and clone handlers are set to NULL. I dont know why, but they do not
- // seem to be necessary...
- _handle = zend_objects_store_put(result, (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
-
- // done
- return result;
-}
+//MixedObject *Base::store(zend_class_entry *entry TSRMLS_DC)
+//{
+// // allocate memory for the object
+// MixedObject *result = (MixedObject *)emalloc(sizeof(MixedObject));
+//
+// // store the new c++ object
+// result->cpp = this;
+//
+// // store the class entry in the newly created object
+// result->php.ce = entry;
+//
+// // initialize the object
+// zend_object_std_init(&result->php, entry TSRMLS_CC);
+//
+//#if PHP_VERSION_ID < 50399
+//
+// // tmp variable
+// zval *tmp;
+//
+// // initialize the properties, php 5.3 way
+// zend_hash_copy(result->php.properties, &entry->default_properties, (copy_ctor_func_t) zval_property_ctor, &tmp, sizeof(zval*));
+//
+//#else
+//
+// // version higher than 5.3 have an easier way to initialize
+// object_properties_init(&result->php, entry);
+//
+//#endif
+//
+//#ifdef ZTS
+//
+// // when in thread safety mode, the destruct method and free method have
+// // an extra parameter holding thread information
+// using DestructType = void(zend_object*,unsigned int,void***);
+// using FreeType = void(zend_object*,void***);
+//
+//#else
+//
+// // not in thread mode: no special parameter for the tsrm_ls variable
+// using DestructType = void(zend_object*,unsigned int);
+// using FreeType = void(zend_object*);
+//
+//#endif
+//
+// // store the two destruct methods in temporary vars
+// DestructType *destructMethod = &ClassImpl::destructObject;
+// FreeType *freeMethod = &ClassImpl::freeObject;
+//
+// // the destructor and clone handlers are set to NULL. I dont know why, but they do not
+// // seem to be necessary...
+// _handle = zend_objects_store_put(result, (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
+//
+// // done
+// return result;
+//}
/**
* Overridable method that is called right before an object is destructed
diff --git a/src/boolmember.h b/zend/boolmember.h
index 5b5d43d..5b5d43d 100644
--- a/src/boolmember.h
+++ b/zend/boolmember.h
diff --git a/src/callable.cpp b/zend/callable.cpp
index 5e37df7..96f5f90 100644
--- a/src/callable.cpp
+++ b/zend/callable.cpp
@@ -23,7 +23,7 @@ namespace Php {
* @param tsrm_ls
* @return integer
*/
-static void invoke_callable(INTERNAL_FUNCTION_PARAMETERS)
+void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
{
// find the function name
const char *name = get_active_function_name(TSRMLS_C);
@@ -31,22 +31,27 @@ static void invoke_callable(INTERNAL_FUNCTION_PARAMETERS)
// uncover the hidden pointer inside the function name
Callable *callable = HiddenPointer<Callable>(name);
- // wrap the return value
- Value result(return_value, true);
-
// construct parameters
- Parameters params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
+ ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
// the function could throw an exception
try
{
// get the result
- result = callable->invoke(params);
+ Value result(callable->invoke(params));
+
+ // detach the zval (we don't want it to be destructed)
+ zval *val = result.detach();
+
+ // @todo php 5.6 has a RETVAL_ZVAL_FAST macro that can be used instead (and is faster)
+
+ // return a full copy of the zval, and do not destruct it
+ RETVAL_ZVAL(val, 1, 0);
}
catch (Exception &exception)
{
// process the exception
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -64,7 +69,7 @@ void Callable::initialize(zend_function_entry *entry, const char *classname, int
{
// fill the members of the entity, and hide a pointer to the current object in the name
entry->fname = (const char *)_ptr;
- entry->handler = invoke_callable;
+ entry->handler = &Callable::invoke;
entry->arg_info = _argv;
entry->num_args = _argc;
entry->flags = flags;
diff --git a/src/callable.h b/zend/callable.h
index f123c8b..67863a9 100644
--- a/src/callable.h
+++ b/zend/callable.h
@@ -9,12 +9,6 @@
*/
/**
- * Forward definitions
- */
-struct _zend_function_entry;
-struct _zend_arg_info;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -43,11 +37,11 @@ public:
// loop through the arguments
for (auto it = arguments.begin(); it != arguments.end(); it++)
{
- // increment required
+ // increment counter with number of required parameters
if (it->required()) _required++;
// fill the arg info
- it->fill(&_argv[i++]);
+ fill(&_argv[i], *it);
}
}
@@ -99,7 +93,7 @@ public:
* @param classname Optional class name
* @param flags Access flags
*/
- void initialize(struct _zend_function_entry *entry, const char *classname = nullptr, int flags = 0) const;
+ void initialize(zend_function_entry *entry, const char *classname = nullptr, int flags = 0) const;
/**
* Fill function info
@@ -107,7 +101,7 @@ public:
* @param ns Active namespace
* @param classname Optional class name
*/
- void initialize(struct _zend_arg_info *info, const char *classname = nullptr) const;
+ void initialize(zend_arg_info *info, const char *classname = nullptr) const;
protected:
@@ -139,7 +133,66 @@ protected:
* The arguments
* @var zend_arg_info[]
*/
- struct _zend_arg_info *_argv = nullptr;
+ zend_arg_info *_argv = nullptr;
+
+ /**
+ * Private helper method to fill an argument object
+ * @param info object from the zend engine
+ * @param arg original object
+ */
+ void fill(zend_arg_info *info, const Argument &arg) const
+ {
+ // fill members
+ info->name = arg.name().c_str();
+ info->name_len = arg.name().size();
+
+#if PHP_VERSION_ID >= 50400
+
+ // since php 5.4 there is a type-hint, but we only support arrays, objects and callables
+ switch (arg.type()) {
+ case Type::Array: info->type_hint = IS_ARRAY; break;
+ case Type::Callable: info->type_hint = IS_CALLABLE; break;
+ case Type::Object: info->type_hint = IS_OBJECT; break;
+ default: info->type_hint = IS_NULL; break;
+ }
+
+# if PHP_VERSION_ID >= 50600
+
+ // from PHP 5.6 and onwards, an is_variadic property can be set, this
+ // specifies whether this argument is the first argument that specifies
+ // the type for a variable length list of arguments. For now we only
+ // support methods and functions with a fixed number of arguments.
+ info->is_variadic = false;
+
+# endif
+
+#else
+
+ // php 5.3 code
+ info->array_type_hint = arg.type() == Type::Array;
+ info->return_reference = false;
+ info->required_num_args = 0; // @todo is this correct?
+
+#endif
+
+ // this parameter is a regular type
+ info->class_name = arg.type() == Type::Object ? arg.classname().c_str() : nullptr;
+ info->class_name_len = arg.type() == Type::Object ? arg.classname().size() : 0;
+ info->allow_null = arg.allowNull();
+ info->pass_by_reference = arg.byReference();
+ }
+
+ /**
+ * Function that is called by the Zend engine every time that a function gets called
+ * @param ht
+ * @param return_value
+ * @param return_value_ptr
+ * @param this_ptr
+ * @param return_value_used
+ * @param tsrm_ls
+ * @return integer
+ */
+ static void invoke(INTERNAL_FUNCTION_PARAMETERS);
};
diff --git a/src/classbase.cpp b/zend/classbase.cpp
index 18d81d5..18d81d5 100644
--- a/src/classbase.cpp
+++ b/zend/classbase.cpp
diff --git a/src/classimpl.cpp b/zend/classimpl.cpp
index 3999cf3..d63956a 100644
--- a/src/classimpl.cpp
+++ b/zend/classimpl.cpp
@@ -28,11 +28,15 @@ ClassImpl::~ClassImpl()
}
/**
+ * @todo refactor so that methods become simpler
+ */
+
+/**
* Retrieve our C++ implementation object
* @param entry
* @return ClassImpl
*/
-static ClassImpl *cpp_impl(zend_class_entry *entry)
+static ClassImpl *self(zend_class_entry *entry)
{
// we need the base class (in user space the class may have been overridden,
// but we are not interested in these user space classes)
@@ -52,34 +56,6 @@ static ClassImpl *cpp_impl(zend_class_entry *entry)
}
/**
- * Retrieve the extension's class object
- * @param entry
- * @return ClassBase
- */
-ClassBase *ClassImpl::base(zend_class_entry *entry)
-{
- // first the implementation class
- ClassImpl *impl = cpp_impl(entry);
-
- // and now the base
- return impl->_base;
-}
-
-/**
- * Retrieve the CPP object
- * @param val
- * @return Base
- */
-static Base *cpp_object(const zval *val TSRMLS_DC)
-{
- // retrieve the old object, which we are going to copy
- MixedObject *object = (MixedObject *)zend_object_store_get_object(val TSRMLS_CC);
-
- // return the cpp object
- return object->cpp;
-}
-
-/**
* Extended zend_internal_function structure that we use to store an
* instance of the ClassBase object. We need this for static method calls
*/
@@ -121,7 +97,7 @@ void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS)
Value result(return_value, true);
// construct parameters
- Parameters params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
+ ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
// retrieve the base object
Base *base = params.object();
@@ -138,7 +114,7 @@ void ClassImpl::callMethod(INTERNAL_FUNCTION_PARAMETERS)
catch (Exception &exception)
{
// process the exception
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -167,7 +143,7 @@ void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS)
Value result(return_value, true);
// construct parameters
- Parameters params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
+ ParametersImpl params(this_ptr, ZEND_NUM_ARGS() TSRMLS_CC);
// retrieve the base object
Base *base = params.object();
@@ -179,12 +155,11 @@ void ClassImpl::callInvoke(INTERNAL_FUNCTION_PARAMETERS)
{
// because of the two-step nature, we are going to report the error ourselves
zend_error(E_ERROR, "Function name must be a string");
-
}
catch (Exception &exception)
{
// process the exception
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -244,7 +219,7 @@ zend_function *ClassImpl::getMethod(zval **object_ptr, char *method_name, int me
function->function_name = method_name;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// done (cast to zend_function* is allowed, because a zend_function is a union
// that has one member being a zend_internal_function)
@@ -289,7 +264,7 @@ zend_function *ClassImpl::getStaticMethod(zend_class_entry *entry, char* method,
function->function_name = method;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// done (cast to zend_function* is allowed, because a zend_function is a union
// that has one member being a zend_internal_function)
@@ -334,7 +309,7 @@ int ClassImpl::getClosure(zval *object, zend_class_entry **entry_ptr, zend_funct
function->function_name = nullptr;
// store pointer to ourselves
- data->self = cpp_impl(entry);
+ data->self = self(entry);
// assign this dynamically allocated variable to the func parameter
// the case is ok, because zend_internal_function is a member of the
@@ -405,31 +380,31 @@ zend_object_handlers *ClassImpl::objectHandlers()
/**
* Function to compare two objects
- * @param object1
- * @param object2
+ * @param val1
+ * @param val2
* @param tsrm_ls
* @return int
*/
-int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
+int ClassImpl::compare(zval *val1, zval *val2 TSRMLS_DC)
{
// prevent exceptions
try
{
// retrieve the class entry linked to this object
- auto *entry = zend_get_class_entry(object1 TSRMLS_CC);
+ auto *entry = zend_get_class_entry(val1 TSRMLS_CC);
// other object must be of the same type
- if (entry != zend_get_class_entry(object2 TSRMLS_CC)) throw NotImplemented();
+ if (entry != zend_get_class_entry(val2 TSRMLS_CC)) throw NotImplemented();
// we need the C++ class meta-information object
- ClassBase *meta = base(entry);
+ ClassBase *meta = self(entry)->_base;
// get the base objects
- Base *base1 = cpp_object(object1 TSRMLS_CC);
- Base *base2 = cpp_object(object2 TSRMLS_CC);
+ Base *object1 = ObjectImpl::find(val1 TSRMLS_CC)->object();
+ Base *object2 = ObjectImpl::find(val2 TSRMLS_CC)->object();
// run the compare method
- return meta->callCompare(base1, base2);
+ return meta->callCompare(object1, object2);
}
catch (const NotImplemented &exception)
{
@@ -437,13 +412,13 @@ int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
if (!std_object_handlers.compare_objects) return 1;
// call default
- return std_object_handlers.compare_objects(object1, object2 TSRMLS_CC);
+ return std_object_handlers.compare_objects(val1, val2 TSRMLS_CC);
}
catch (Exception &exception)
{
// a Php::Exception was thrown by the extension __compare function,
// pass this on to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// what shall we return here...
return 1;
@@ -452,22 +427,22 @@ int ClassImpl::compare(zval *object1, zval *object2 TSRMLS_DC)
/**
* Function to cast the object to a different type
- * @param object
+ * @param val
* @param retval
* @param type
* @param tsrm_ls
* @return int
*/
-int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
+int ClassImpl::cast(zval *val, zval *retval, int type TSRMLS_DC)
{
- // get the base object
- Base *base = cpp_object(object TSRMLS_CC);
+ // get the base c++ object
+ Base *object = ObjectImpl::find(val TSRMLS_CC)->object();
// retrieve the class entry linked to this object
- auto *entry = zend_get_class_entry(object TSRMLS_CC);
+ auto *entry = zend_get_class_entry(val TSRMLS_CC);
// we need the C++ class meta-information object
- ClassBase *meta = ClassImpl::base(entry);
+ ClassBase *meta = self(entry)->_base;
// retval it not yet initialized --- and again feelings of disbelief,
// frustration, wonder and anger come up when you see that there are not two
@@ -486,18 +461,18 @@ int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
// check type
switch ((Type)type) {
- case Type::Numeric: result = meta->callToInteger(base).detach(); break;
- case Type::Float: result = meta->callToFloat(base).detach(); break;
- case Type::Bool: result = meta->callToBool(base).detach(); break;
- case Type::String: result = meta->callToString(base).detach(); break;
+ case Type::Numeric: result = meta->callToInteger(object).detach(); break;
+ case Type::Float: result = meta->callToFloat(object).detach(); break;
+ case Type::Bool: result = meta->callToBool(object).detach(); break;
+ case Type::String: result = meta->callToString(object).detach(); break;
default: throw NotImplemented(); break;
}
// @todo do we turn into endless conversion if the __toString object returns 'this' ??
// (and if it does: who cares? If the extension programmer is stupid, why do we have to suffer?)
- // is the object overwritten?
- if (object == retval) zval_dtor(object);
+ // is the original parameter overwritten?
+ if (val == retval) zval_dtor(val);
// overwrite the result
ZVAL_ZVAL(retval, result, 1, 1);
@@ -511,12 +486,12 @@ int ClassImpl::cast(zval *object, zval *retval, int type TSRMLS_DC)
if (!std_object_handlers.cast_object) return FAILURE;
// call default
- return std_object_handlers.cast_object(object, retval, type TSRMLS_CC);
+ return std_object_handlers.cast_object(val, retval, type TSRMLS_CC);
}
catch (Exception &exception)
{
// pass on the exception to php userspace
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// done
return FAILURE;
@@ -534,14 +509,14 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
auto *entry = zend_get_class_entry(val TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// retrieve the old object, which we are going to copy
- MixedObject *old_object = (MixedObject *)zend_object_store_get_object(val TSRMLS_CC);
+ ObjectImpl *old_object = ObjectImpl::find(val TSRMLS_CC);
// create a new base c++ object
- auto *cpp = meta->clone(old_object->cpp);
+ auto *cpp = meta->clone(old_object->object());
// 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
@@ -555,14 +530,14 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
result.handlers = impl->objectHandlers();
// store the object
- MixedObject *new_object = cpp->store(entry TSRMLS_CC);
+ ObjectImpl *new_object = new ObjectImpl(entry, cpp TSRMLS_CC);
// store the object in the object cache
- result.handle = cpp->handle();
+ result.handle = new_object->handle();
// clone the members (this will also call the __clone() function if the user
// had registered that as a visible method)
- zend_objects_clone_members(&new_object->php, result, &old_object->php, Z_OBJ_HANDLE_P(val) TSRMLS_CC);
+ zend_objects_clone_members(new_object->php(), result, old_object->php(), Z_OBJ_HANDLE_P(val) TSRMLS_CC);
// was a custom clone method installed? If not we call the magic c++ __clone method
if (!entry->clone) meta->callClone(cpp);
@@ -584,7 +559,7 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
int ClassImpl::countElements(zval *object, long *count TSRMLS_DC)
{
// does it implement the countable interface?
- Countable *countable = dynamic_cast<Countable*>(cpp_object(object TSRMLS_CC));
+ Countable *countable = dynamic_cast<Countable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the Countable interface, we rely on the default implementation
if (countable)
@@ -601,7 +576,7 @@ int ClassImpl::countElements(zval *object, long *count TSRMLS_DC)
catch (Exception &exception)
{
// process the exception
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return FAILURE;
@@ -650,7 +625,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC)
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -664,7 +639,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC)
catch (Exception &exception)
{
// process the exception (send it to user space)
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return Value(nullptr).detach();
@@ -695,7 +670,7 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type TSRMLS_DC)
void ClassImpl::writeDimension(zval *object, zval *offset, zval *value TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -709,7 +684,7 @@ void ClassImpl::writeDimension(zval *object, zval *offset, zval *value TSRMLS_DC
catch (Exception &exception)
{
// process the exception (send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
else
@@ -737,7 +712,7 @@ void ClassImpl::writeDimension(zval *object, zval *offset, zval *value TSRMLS_DC
int ClassImpl::hasDimension(zval *object, zval *member, int check_empty TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -758,7 +733,7 @@ int ClassImpl::hasDimension(zval *object, zval *member, int check_empty TSRMLS_D
catch (Exception &exception)
{
// process the exception (send it to user space)
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return false;
@@ -787,7 +762,7 @@ int ClassImpl::hasDimension(zval *object, zval *member, int check_empty TSRMLS_D
void ClassImpl::unsetDimension(zval *object, zval *member TSRMLS_DC)
{
// does it implement the arrayaccess interface?
- ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(cpp_object(object TSRMLS_CC));
+ ArrayAccess *arrayaccess = dynamic_cast<ArrayAccess*>(ObjectImpl::find(object TSRMLS_CC)->object());
// if it does not implement the ArrayAccess interface, we rely on the default implementation
if (arrayaccess)
@@ -801,7 +776,7 @@ void ClassImpl::unsetDimension(zval *object, zval *member TSRMLS_DC)
catch (Exception &exception)
{
// process the exception (send it to user space)
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
else
@@ -871,13 +846,13 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit
// that is in most cases simply impossible.
// retrieve the object and class
- Base *base = cpp_object(object TSRMLS_CC);
+ Base *base = ObjectImpl::find(object TSRMLS_CC)->object();
// retrieve the class entry linked to this object
auto *entry = zend_get_class_entry(object TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// the default implementation throws an exception, so by catching
@@ -918,7 +893,7 @@ zval *ClassImpl::readProperty(zval *object, zval *name, int type, const zend_lit
{
// user threw an exception in its magic method
// implementation, send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return Value(nullptr).detach();
@@ -945,13 +920,13 @@ void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_
#endif
{
// retrieve the object and class
- Base *base = cpp_object(object TSRMLS_CC);
+ Base *base = ObjectImpl::find(object TSRMLS_CC)->object();
// retrieve the class entry linked to this object
auto *entry = zend_get_class_entry(object TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// the default implementation throws an exception, if we catch that
@@ -995,7 +970,7 @@ void ClassImpl::writeProperty(zval *object, zval *name, zval *value, const zend_
{
// user threw an exception in its magic method
// implementation, send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -1030,13 +1005,13 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z
try
{
// get the cpp object
- Base *base = cpp_object(object TSRMLS_CC);
+ Base *base = ObjectImpl::find(object TSRMLS_CC)->object();
// retrieve the class entry linked to this object
auto *entry = zend_get_class_entry(object TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
ClassBase *meta = impl->_base;
// convert the name to a Value object
@@ -1076,7 +1051,7 @@ int ClassImpl::hasProperty(zval *object, zval *name, int has_set_exists, const z
{
// user threw an exception in its magic method
// implementation, send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return false;
@@ -1107,7 +1082,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
auto *entry = zend_get_class_entry(object TSRMLS_CC);
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
// property name
Value name(member);
@@ -1116,7 +1091,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
auto iter = impl->_properties.find(name);
// if the property does not exist, we forward to the __unset
- if (iter == impl->_properties.end()) impl->_base->callUnset(cpp_object(object TSRMLS_CC), member);
+ if (iter == impl->_properties.end()) impl->_base->callUnset(ObjectImpl::find(object TSRMLS_CC)->object(), member);
// callback properties cannot be unset
zend_error(E_ERROR, "Property %s can not be unset", (const char *)name);
@@ -1137,7 +1112,7 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
{
// user threw an exception in its magic method
// implementation, send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -1150,17 +1125,17 @@ void ClassImpl::unsetProperty(zval *object, zval *member, const zend_literal *ke
*/
void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TSRMLS_DC)
{
- // allocate memory for the object
- MixedObject *obj = (MixedObject *)object;
+ // find object
+ ObjectImpl *obj = ObjectImpl::find(object);
// get meta info
- ClassImpl *impl = cpp_impl(object->ce);
+ ClassImpl *impl = self(object->ce);
// prevent exceptions
try
{
// call the destruct function
- if (obj->cpp) impl->_base->callDestruct(obj->cpp);
+ if (obj->object()) impl->_base->callDestruct(obj->object());
}
catch (const NotImplemented &exception)
{
@@ -1171,7 +1146,7 @@ void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TS
{
// a regular Php::Exception was thrown by the extension, pass it on
// to PHP user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
}
}
@@ -1183,13 +1158,10 @@ void ClassImpl::destructObject(zend_object *object, zend_object_handle handle TS
void ClassImpl::freeObject(zend_object *object TSRMLS_DC)
{
// allocate memory for the object
- MixedObject *obj = (MixedObject *)object;
-
- // deallocate the cpp object
- if (obj->cpp) delete obj->cpp;
+ ObjectImpl *obj = ObjectImpl::find(object);
- // pass on to the default destructor
- zend_objects_free_object_storage(object TSRMLS_CC);
+ // no longer need it
+ obj->destruct(TSRMLS_C);
}
/**
@@ -1202,7 +1174,7 @@ void ClassImpl::freeObject(zend_object *object TSRMLS_DC)
zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC)
{
// we need the C++ class meta-information object
- ClassImpl *impl = cpp_impl(entry);
+ ClassImpl *impl = self(entry);
// create a new base C++ object
auto *cpp = impl->_base->construct();
@@ -1216,11 +1188,11 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC)
// set the handlers
result.handlers = impl->objectHandlers();
- // store the object
- cpp->store(entry TSRMLS_CC);
-
+ // create the object in the zend engine
+ ObjectImpl *object = new ObjectImpl(entry, cpp TSRMLS_CC);
+
// store the object in the object cache
- result.handle = cpp->handle();
+ result.handle = object->handle();
// done
return result;
@@ -1240,13 +1212,13 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
if (by_ref) throw Php::Exception("Foreach by ref is not possible");
// retrieve the traversable object
- Traversable *traversable = dynamic_cast<Traversable*>(cpp_object(object TSRMLS_CC));
+ Traversable *traversable = dynamic_cast<Traversable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// user may throw an exception in the getIterator() function
try
{
// create an iterator
- auto *iterator = traversable->getIterator();
+ auto *iterator = new IteratorImpl(traversable->getIterator());
// return the implementation
return iterator->implementation();
@@ -1255,7 +1227,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
{
// user threw an exception in its method
// implementation, send it to user space
- exception.process(TSRMLS_C);
+ process(exception TSRMLS_CC);
// unreachable
return nullptr;
@@ -1274,7 +1246,7 @@ zend_object_iterator *ClassImpl::getIterator(zend_class_entry *entry, zval *obje
int ClassImpl::serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
{
// get the serializable object
- Serializable *serializable = dynamic_cast<Serializable*>(cpp_object(object TSRMLS_CC));
+ Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(object TSRMLS_CC)->object());
// call the serialize method on the object
auto value = serializable->serialize();
@@ -1304,7 +1276,7 @@ int ClassImpl::unserialize(zval **object, zend_class_entry *entry, const unsigne
object_init_ex(*object, entry);
// turn this into a serializale
- Serializable *serializable = dynamic_cast<Serializable*>(cpp_object(*object TSRMLS_CC));
+ Serializable *serializable = dynamic_cast<Serializable*>(ObjectImpl::find(*object TSRMLS_CC)->object());
// call the unserialize method on it
serializable->unserialize((const char *)buffer, buf_len);
diff --git a/src/classimpl.h b/zend/classimpl.h
index cf28199..febdbca 100644
--- a/src/classimpl.h
+++ b/zend/classimpl.h
@@ -134,13 +134,6 @@ public:
}
/**
- * Retrieve the extension's class object
- * @param entry
- * @return ClassBase
- */
- static ClassBase *base(zend_class_entry *entry);
-
- /**
* Initialize the class, given its name
*
* The module functions are registered on module startup, but classes are
diff --git a/zend/extension.cpp b/zend/extension.cpp
new file mode 100644
index 0000000..9685b32
--- /dev/null
+++ b/zend/extension.cpp
@@ -0,0 +1,103 @@
+/**
+ * Extension.cpp
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013, 2014 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Constructor that defines a number of functions right away
+ * @param name Extension name
+ * @param version Extension version string
+ */
+Extension::Extension(const char *name, const char *version) :
+ Namespace(""), _impl(new ExtensionImpl(this, name, version)) {}
+
+/**
+ * Destructor
+ */
+Extension::~Extension()
+{
+ // get rid of the implementation object
+ delete _impl;
+}
+
+/**
+ * Register a function to be called when the PHP engine is ready
+ * @param callback
+ * @return Extension
+ */
+Extension &Extension::onStartup(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onStartup(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a function to be called when the PHP engine is going to stop
+ * @param callback
+ * @return Extension
+ */
+Extension &Extension::onShutdown(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onShutdown(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a callback that is called at the beginning of each pageview/request
+ * @param callback
+ */
+Extension &Extension::onRequest(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onRequest(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Register a callback that is called to cleanup things after a pageview/request
+ * @param callback
+ */
+Extension &Extension::onIdle(const Callback &callback)
+{
+ // pass on to the implementation
+ _impl->onIdle(callback);
+
+ // allow chaining
+ return *this;
+}
+
+/**
+ * Retrieve the module pointer
+ *
+ * This is the memory address that should be exported by the get_module()
+ * function.
+ *
+ * @return void*
+ */
+void *Extension::module()
+{
+ // pass on to the implementation
+ return _impl->module();
+}
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/src/extension.cpp b/zend/extensionimpl.cpp
index 2782f3f..3534cdb 100644
--- a/src/extension.cpp
+++ b/zend/extensionimpl.cpp
@@ -51,8 +51,8 @@ static void init_globals(zend_phpcpp_globals *globals) {}
*
* @var map
*/
-static std::map<std::string,Extension*> name2extension;
-static std::map<int,Extension*> number2extension;
+static std::map<std::string,ExtensionImpl*> name2extension;
+static std::map<int,ExtensionImpl*> number2extension;
/**
* Handler function that is used in combination with zend_hash_apply()
@@ -61,9 +61,9 @@ static std::map<int,Extension*> number2extension;
* an extension number. We loop through the list of all registered modules, and
* for each module we check if we know the extension based on the name
*
- * @param _zend_module_entry
+ * @param zend_module_entry
*/
-static int match_module(_zend_module_entry *entry)
+static int match_module(zend_module_entry *entry)
{
// check if there is an extension with this name
auto iter = name2extension.find(entry->name);
@@ -82,7 +82,7 @@ static int match_module(_zend_module_entry *entry)
* @param tsrm_ls
* @return Extension*
*/
-static Extension *find(int number TSRMLS_DC)
+static ExtensionImpl *find(int number TSRMLS_DC)
{
// do we already have an extension with this number?
auto iter = number2extension.find(number);
@@ -106,14 +106,14 @@ static Extension *find(int number TSRMLS_DC)
* @param tsrm_ls
* @return int 0 on success
*/
-int Extension::onStartup(int type, int module_number TSRMLS_DC)
+int ExtensionImpl::processStartup(int type, int module_number TSRMLS_DC)
{
// initialize and allocate the "global" variables
ZEND_INIT_MODULE_GLOBALS(phpcpp, init_globals, NULL);
// get the extension
- Extension *extension = find(module_number TSRMLS_CC);
+ auto *extension = find(module_number TSRMLS_CC);
// array contains ini settings
static zend_ini_entry *ini_entries = new zend_ini_entry[ extension->_ini_entries.size()+1 ];
@@ -129,8 +129,8 @@ int Extension::onStartup(int type, int module_number TSRMLS_DC)
// register
REGISTER_INI_ENTRIES();
- // initialize namespace
- extension->initialize("" TSRMLS_CC);
+ // initialize the extension
+ extension->initialize(TSRMLS_C);
// is the callback registered?
if (extension->_onStartup) extension->_onStartup();
@@ -146,10 +146,10 @@ int Extension::onStartup(int type, int module_number TSRMLS_DC)
* @param tsrm_ls
* @return int
*/
-int Extension::onShutdown(int type, int module_number TSRMLS_DC)
+int ExtensionImpl::processShutdown(int type, int module_number TSRMLS_DC)
{
// get the extension
- Extension *extension = find(module_number TSRMLS_CC);
+ auto *extension = find(module_number TSRMLS_CC);
UNREGISTER_INI_ENTRIES();
@@ -171,10 +171,10 @@ int Extension::onShutdown(int type, int module_number TSRMLS_DC)
* @param tsrm_ls
* @return int 0 on success
*/
-int Extension::onRequest(int type, int module_number TSRMLS_DC)
+int ExtensionImpl::processRequest(int type, int module_number TSRMLS_DC)
{
// get the extension
- Extension *extension = find(module_number TSRMLS_CC);
+ auto *extension = find(module_number TSRMLS_CC);
// is the callback registered?
if (extension->_onRequest) extension->_onRequest();
@@ -190,10 +190,10 @@ int Extension::onRequest(int type, int module_number TSRMLS_DC)
* @param tsrm_ls
* @return int 0 on success
*/
-int Extension::onIdle(int type, int module_number TSRMLS_DC)
+int ExtensionImpl::processIdle(int type, int module_number TSRMLS_DC)
{
// get the extension
- Extension *extension = find(module_number TSRMLS_CC);
+ auto *extension = find(module_number TSRMLS_CC);
// is the callback registered?
if (extension->_onIdle) extension->_onIdle();
@@ -204,52 +204,45 @@ int Extension::onIdle(int type, int module_number TSRMLS_DC)
/**
* Constructor
+ * @param data Pointer to the extension object created by the extension programmer
* @param name Name of the extension
* @param version Version number
- * @param start Request start callback
- * @param stop Request stop callback
*/
-Extension::Extension(const char *name, const char *version) : Namespace("")
+ExtensionImpl::ExtensionImpl(Extension *data, const char *name, const char *version) : ExtensionBase(data)
{
// keep extension pointer based on the name
name2extension[name] = this;
- // allocate memory (we allocate this on the heap so that the size of the
- // entry does not have to be defined in the .h file. We pay a performance
- // price for this, but we pay this price becuase the design goal of the
- // PHP-C++ library is to have an interface that is as simple as possible
- _entry = new _zend_module_entry;
-
// assign all members (apart from the globals)
- _entry->size = sizeof(zend_module_entry); // size of the data
- _entry->zend_api = ZEND_MODULE_API_NO; // api number
- _entry->zend_debug = ZEND_DEBUG; // debug mode enabled?
- _entry->zts = USING_ZTS; // is thread safety enabled?
- _entry->ini_entry = NULL; // the php.ini record, will be filled by Zend engine
- _entry->deps = NULL; // dependencies on other modules
- _entry->name = name; // extension name
- _entry->functions = NULL; // functions supported by this module (none for now)
- _entry->module_startup_func = &Extension::onStartup; // startup function for the whole extension
- _entry->module_shutdown_func = &Extension::onShutdown; // shutdown function for the whole extension
- _entry->request_startup_func = &Extension::onRequest; // startup function per request
- _entry->request_shutdown_func = &Extension::onIdle; // shutdown function per request
- _entry->info_func = NULL; // information for retrieving info
- _entry->version = version; // version string
- _entry->globals_size = 0; // size of the global variables
- _entry->globals_ctor = NULL; // constructor for global variables
- _entry->globals_dtor = NULL; // destructor for global variables
- _entry->post_deactivate_func = NULL; // unknown function
- _entry->module_started = 0; // module is not yet started
- _entry->type = 0; // temporary or persistent module, will be filled by Zend engine
- _entry->handle = NULL; // dlopen() handle, will be filled by Zend engine
- _entry->module_number = 0; // module number will be filled in by Zend engine
- _entry->build_id = (char *)ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible
+ _entry.size = sizeof(zend_module_entry); // size of the data
+ _entry.zend_api = ZEND_MODULE_API_NO; // api number
+ _entry.zend_debug = ZEND_DEBUG; // debug mode enabled?
+ _entry.zts = USING_ZTS; // is thread safety enabled?
+ _entry.ini_entry = NULL; // the php.ini record, will be filled by Zend engine
+ _entry.deps = NULL; // dependencies on other modules
+ _entry.name = name; // extension name
+ _entry.functions = NULL; // functions supported by this module (none for now)
+ _entry.module_startup_func = &ExtensionImpl::processStartup; // startup function for the whole extension
+ _entry.module_shutdown_func = &ExtensionImpl::processShutdown; // shutdown function for the whole extension
+ _entry.request_startup_func = &ExtensionImpl::processRequest; // startup function per request
+ _entry.request_shutdown_func = &ExtensionImpl::processIdle; // shutdown function per request
+ _entry.info_func = NULL; // information for retrieving info
+ _entry.version = version; // version string
+ _entry.globals_size = 0; // size of the global variables
+ _entry.globals_ctor = NULL; // constructor for global variables
+ _entry.globals_dtor = NULL; // destructor for global variables
+ _entry.post_deactivate_func = NULL; // unknown function
+ _entry.module_started = 0; // module is not yet started
+ _entry.type = 0; // temporary or persistent module, will be filled by Zend engine
+ _entry.handle = NULL; // dlopen() handle, will be filled by Zend engine
+ _entry.module_number = 0; // module number will be filled in by Zend engine
+ _entry.build_id = (char *)ZEND_MODULE_BUILD_ID; // check if extension and zend engine are compatible
// things that only need to be initialized
#ifdef ZTS
- _entry->globals_id_ptr = NULL;
+ _entry.globals_id_ptr = NULL;
#else
- _entry->globals_ptr = NULL;
+ _entry.globals_ptr = NULL;
#endif
}
@@ -257,29 +250,42 @@ Extension::Extension(const char *name, const char *version) : Namespace("")
/**
* Destructor
*/
-Extension::~Extension()
+ExtensionImpl::~ExtensionImpl()
{
// deallocate functions
- if (_entry->functions) delete[] _entry->functions;
-
- // deallocate entry
- delete _entry;
+ if (_entry.functions) delete[] _entry.functions;
}
/**
* Retrieve the module entry
* @return zend_module_entry
*/
-zend_module_entry *Extension::module()
+zend_module_entry *ExtensionImpl::module()
{
// check if functions we're already defined
- if (_entry->functions || _functions.size() == 0) return _entry;
+ if (_entry.functions) return &_entry;
+
+ // the number of functions
+ int count = _data->functions();
+
+ // skip if there are no functions
+ if (count == 0) return &_entry;
// allocate memory for the functions
- zend_function_entry *entries = new zend_function_entry[functions() + 1];
+ zend_function_entry *entries = new zend_function_entry[count + 1];
+
+ // index being processed
+ int i = 0;
- // initialize the entries
- int count = Namespace::initialize("", entries);
+ // apply a function to each function
+ _data->apply([&i, entries](const std::string &prefix, Function &function) {
+
+ // initialize the function
+ function.initialize(prefix, &entries[i]);
+
+ // move on to the next iteration
+ i++;
+ });
// last entry should be set to all zeros
zend_function_entry *last = &entries[count];
@@ -288,10 +294,24 @@ zend_module_entry *Extension::module()
memset(last, 0, sizeof(zend_function_entry));
// store functions in entry object
- _entry->functions = entries;
+ _entry.functions = entries;
// return the entry
- return _entry;
+ return &_entry;
+}
+
+/**
+ * Initialize the extension after it was started
+ * @param tsrm_ls
+ */
+void ExtensionImpl::initialize(TSRMLS_D)
+{
+ // we need to register each class, find out all classes
+ _data->apply([TSRMLS_C](const std::string &prefix, ClassBase &c) {
+
+ // forward to implementation class
+ c.implementation()->initialize(&c, prefix TSRMLS_CC);
+ });
}
/**
diff --git a/zend/extensionimpl.h b/zend/extensionimpl.h
new file mode 100644
index 0000000..e58ce66
--- /dev/null
+++ b/zend/extensionimpl.h
@@ -0,0 +1,120 @@
+/**
+ * ExtensionImpl.h
+ *
+ * Extension implementation for the Zend engine.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013, 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ExtensionImpl : public ExtensionBase
+{
+protected:
+ /**
+ * The information that is passed to the Zend engine
+ *
+ * Although it would be slightly faster to not make this a pointer, this
+ * would require that client code also includes the PHP header files, which
+ * we try to prevent with the PHP-CPP library, so we allocate it dynamically.
+ *
+ * @var zend_module_entry
+ */
+ zend_module_entry _entry;
+
+public:
+ /**
+ * Constructor
+ * @param data Extension object created by the extension programmer
+ * @param name Name of the extension
+ * @param version Version number
+ */
+ ExtensionImpl(Extension *data, const char *name, const char *version);
+
+ /**
+ * No copy'ing and no moving
+ */
+ ExtensionImpl(const ExtensionImpl &extension) = delete;
+ ExtensionImpl(ExtensionImpl &&extension) = delete;
+
+ /**
+ * Destructor
+ */
+ virtual ~ExtensionImpl();
+
+ /**
+ * Retrieve the module entry
+ *
+ * This is the memory address that should be exported by the get_module()
+ * function.
+ *
+ * @return _zend_module_entry
+ */
+ zend_module_entry *module();
+
+ /**
+ * Cast to a module entry
+ * @return _zend_module_entry*
+ */
+ operator zend_module_entry * ()
+ {
+ return module();
+ }
+
+private:
+ /**
+ * Initialize the namespace after it was registered
+ * @param tsrm_ls
+ */
+ void initialize(TSRMLS_D);
+
+ /**
+ * Function that is called when the extension initializes
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int processStartup(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when the extension is about to be stopped
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int
+ */
+ static int processShutdown(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when a request starts
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int processRequest(int type, int module_number TSRMLS_DC);
+
+ /**
+ * Function that is called when a request is ended
+ * @param type Module type
+ * @param number Module number
+ * @param tsrm_ls
+ * @return int 0 on success
+ */
+ static int processIdle(int type, int module_number TSRMLS_DC);
+};
+
+/**
+ * End of namespace
+ */
+}
+
+
diff --git a/src/floatmember.h b/zend/floatmember.h
index 9b5d4f2..9b5d4f2 100644
--- a/src/floatmember.h
+++ b/zend/floatmember.h
diff --git a/src/function.h b/zend/function.h
index fd60944..4c34ac7 100644
--- a/src/function.h
+++ b/zend/function.h
@@ -67,7 +67,7 @@ public:
* @param prefix Active namespace prefix
* @param entry Entry to be filled
*/
- void initialize(const std::string &prefix, struct _zend_function_entry *entry)
+ void initialize(const std::string &prefix, zend_function_entry *entry)
{
// if there is a namespace prefix, we should adjust the name
if (prefix.size()) _ptr = HiddenPointer<Callable>(this, prefix+"\\"+(const char *)_ptr);
diff --git a/src/global.cpp b/zend/global.cpp
index 7eea8e7..7eea8e7 100644
--- a/src/global.cpp
+++ b/zend/global.cpp
diff --git a/src/globals.cpp b/zend/globals.cpp
index 8132ef3..8132ef3 100644
--- a/src/globals.cpp
+++ b/zend/globals.cpp
diff --git a/src/hashiterator.h b/zend/hashiterator.h
index d68ad4e..b1f409f 100644
--- a/src/hashiterator.h
+++ b/zend/hashiterator.h
@@ -20,7 +20,7 @@ namespace Php {
/**
* Class definition
*/
-class HashIterator : public IteratorImpl
+class HashIterator : public ValueIteratorImpl
{
public:
/**
@@ -70,9 +70,9 @@ public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl
+ * @return ValueIteratorImpl
*/
- virtual IteratorImpl *clone()
+ virtual ValueIteratorImpl *clone()
{
// create a new instance
return new HashIterator(*this);
@@ -136,7 +136,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// this always is a hash iterator
HashIterator *other = (HashIterator *)that;
diff --git a/src/hashmember.cpp b/zend/hashmember.cpp
index f6f8483..f6f8483 100644
--- a/src/hashmember.cpp
+++ b/zend/hashmember.cpp
diff --git a/src/includes.h b/zend/includes.h
index 45cbd2d..e7dece9 100644
--- a/src/includes.h
+++ b/zend/includes.h
@@ -76,12 +76,17 @@
#include "../include/namespace.h"
#include "../include/extension.h"
#include "../include/call.h"
-#include "../include/init.h"
/**
- * Interface files for internal use only
+ * Common header files for internal use only
*/
-#include "mixedobject.h"
+#include "../common/extensionbase.h"
+#include "../common/streambuf.h"
+
+/**
+ * Specific zend implementation files for internal use only
+ */
+#include "init.h"
#include "callable.h"
#include "function.h"
#include "method.h"
@@ -95,12 +100,15 @@
#include "origexception.h"
#include "notimplemented.h"
#include "property.h"
-#include "iteratorimpl.h"
+#include "valueiteratorimpl.h"
#include "hashiterator.h"
#include "invaliditerator.h"
#include "traverseiterator.h"
-#include "streambuf.h"
+#include "iteratorimpl.h"
#include "classimpl.h"
+#include "objectimpl.h"
+#include "parametersimpl.h"
+#include "extensionimpl.h"
#ifndef ZVAL_COPY_VALUE
#define ZVAL_COPY_VALUE(z, v) \
diff --git a/include/init.h b/zend/init.h
index 8f914f5..8f914f5 100644
--- a/include/init.h
+++ b/zend/init.h
diff --git a/src/invaliditerator.h b/zend/invaliditerator.h
index 7531d7d..388eca8 100644
--- a/src/invaliditerator.h
+++ b/zend/invaliditerator.h
@@ -16,15 +16,15 @@ namespace Php {
/**
* Class definition
*/
-class InvalidIterator : public IteratorImpl
+class InvalidIterator : public ValueIteratorImpl
{
public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl
+ * @return ValueIteratorImpl
*/
- virtual IteratorImpl *clone()
+ virtual ValueIteratorImpl *clone()
{
// create a new instance
return new InvalidIterator(*this);
@@ -54,7 +54,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// the other iterator is also an invalid-iterator, and all invalid
// iterators are equal
diff --git a/src/iterator.cpp b/zend/iteratorimpl.cpp
index 0362fb1..2750ddb 100644
--- a/src/iterator.cpp
+++ b/zend/iteratorimpl.cpp
@@ -14,20 +14,24 @@
namespace Php {
/**
+ * Helper method to get access to ourselves
+ * @param iter
+ * @return IteratorImpl
+ */
+static IteratorImpl *self(zend_object_iterator *iter)
+{
+ return (IteratorImpl *)iter->data;
+}
+
+/**
* Iterator destructor method
* @param iter
* @param tsrm_ls
*/
-void Iterator::destructor(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::destructor(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
- // delete the iterator
- delete iterator;
-
- // free memory for the meta object
- efree(iter);
+ // delete the object
+ delete self(iter);
}
/**
@@ -37,13 +41,10 @@ void Iterator::destructor(zend_object_iterator *iter TSRMLS_DC)
* @param tsrm_ls
* @return int
*/
-int Iterator::valid(zend_object_iterator *iter TSRMLS_DC)
+int IteratorImpl::valid(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// check if valid
- return iterator->valid() ? SUCCESS : FAILURE;
+ return self(iter)->valid() ? SUCCESS : FAILURE;
}
/**
@@ -52,10 +53,10 @@ int Iterator::valid(zend_object_iterator *iter TSRMLS_DC)
* @param data
* @param tsrm_ls
*/
-void Iterator::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+void IteratorImpl::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
{
// get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
+ IteratorImpl *iterator = self(iter);
// retrieve the value (and store it in a member so that it is not
// destructed when the function returns)
@@ -74,13 +75,10 @@ void Iterator::current(zend_object_iterator *iter, zval ***data TSRMLS_DC)
* @param key
* @param tsrm_ls
*/
-void Iterator::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
+void IteratorImpl::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// retrieve the key
- Value retval(iterator->key());
+ Value retval(self(iter)->key());
// detach the underlying zval
zval *val = retval.detach();
@@ -98,13 +96,10 @@ void Iterator::key(zend_object_iterator *iter, zval *key TSRMLS_DC)
* @param tsrm_ls
* @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
*/
-int Iterator::key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
+int IteratorImpl::key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// retrieve the key
- Value retval(iterator->key());
+ Value retval(self(iter)->key());
// is this a numeric string?
if (retval.isString())
@@ -131,13 +126,10 @@ int Iterator::key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
* @param iter
* @param tsrm_ls
*/
-void Iterator::next(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::next(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// call the next method
- iterator->next();
+ self(iter)->next();
}
/**
@@ -145,20 +137,17 @@ void Iterator::next(zend_object_iterator *iter TSRMLS_DC)
* @param iter
* @param tsrm_ls
*/
-void Iterator::rewind(zend_object_iterator *iter TSRMLS_DC)
+void IteratorImpl::rewind(zend_object_iterator *iter TSRMLS_DC)
{
- // get the actual iterator
- Iterator *iterator = (Iterator *)iter->data;
-
// call the rewind method
- iterator->rewind();
+ self(iter)->rewind();
}
/**
* Get access to all iterator functions
* @return zend_object_iterator_funcs
*/
-zend_object_iterator_funcs *Iterator::functions()
+zend_object_iterator_funcs *IteratorImpl::functions()
{
// static variable with all functions
static zend_object_iterator_funcs funcs;
@@ -170,12 +159,12 @@ zend_object_iterator_funcs *Iterator::functions()
if (initialized) return &funcs;
// set the members
- funcs.dtor = &Iterator::destructor;
- funcs.valid = &Iterator::valid;
- funcs.get_current_data = &Iterator::current;
- funcs.get_current_key = &Iterator::key;
- funcs.move_forward = &Iterator::next;
- funcs.rewind = &Iterator::rewind;
+ funcs.dtor = &IteratorImpl::destructor;
+ funcs.valid = &IteratorImpl::valid;
+ funcs.get_current_data = &IteratorImpl::current;
+ funcs.get_current_key = &IteratorImpl::key;
+ funcs.move_forward = &IteratorImpl::next;
+ funcs.rewind = &IteratorImpl::rewind;
// invalidate is not yet supported
funcs.invalidate_current = nullptr;
@@ -188,24 +177,6 @@ zend_object_iterator_funcs *Iterator::functions()
}
/**
- * Internal method that returns the implementation object
- * @return zend_object_iterator
- */
-struct _zend_object_iterator *Iterator::implementation()
-{
- // create an iterator
- zend_object_iterator *iterator = (zend_object_iterator *)emalloc(sizeof(zend_object_iterator));
-
- // initialize all properties
- iterator->data = this;
- iterator->index = 0;
- iterator->funcs = functions();
-
- // done
- return iterator;
-}
-
-/**
* End namespace
*/
}
diff --git a/zend/iteratorimpl.h b/zend/iteratorimpl.h
new file mode 100644
index 0000000..0a815e2
--- /dev/null
+++ b/zend/iteratorimpl.h
@@ -0,0 +1,190 @@
+/**
+ * Iterator.h
+ *
+ * Base class for iterators. Extension writers that want to create traversable
+ * classes, should override the Php::Traversable base class. This base class
+ * forces you to implement a getIterator() method that returns an instance of
+ * a Php::Iterator class.
+ *
+ * In this file you find the signature of the Php::Iterator class. It mostly has
+ * pure virtual methods, which means that you should create a derived class
+ * that implements all these methods.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class IteratorImpl
+{
+private:
+ /**
+ * Unique pointer to the iterator that is returned by the extension
+ * @var std::unique_ptr
+ */
+ std::unique_ptr<Iterator> _iterator;
+
+ /**
+ * The current() method that is called by the Zend engine wants a
+ * pointer-to-pointer-to-a-zval. Because of this, we have to keep the
+ * current value in memory after the current() method returns because
+ * the pointer would otherwise fall out of scope. This is (once again)
+ * odd behavior of the Zend engine, but we'll have to live with that
+ * @var Value
+ */
+ Value _current;
+
+ /**
+ * The object iterator as is needed by the Zend engine
+ * @var zend_object_iterator
+ */
+ zend_object_iterator _impl;
+
+ /**
+ * Get access to all iterator functions
+ * @return zend_object_iterator_funcs
+ */
+ static zend_object_iterator_funcs *functions();
+
+ /**
+ * Is the iterator on a valid position
+ * @return bool
+ */
+ bool valid()
+ {
+ return _iterator->valid();
+ }
+
+ /**
+ * The value at the current position
+ * @return Value
+ */
+ Value current()
+ {
+ return _iterator->current();
+ }
+
+ /**
+ * The key at the current position
+ * @return Value
+ */
+ Value key()
+ {
+ return _iterator->key();
+ }
+
+ /**
+ * Move to the next position
+ */
+ void next()
+ {
+ return _iterator->next();
+ }
+
+ /**
+ * Rewind the iterator to the front position
+ */
+ void rewind()
+ {
+ return _iterator->rewind();
+ }
+
+ /**
+ * Iterator destructor method
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void destructor(zend_object_iterator *iter TSRMLS_DC);
+
+ /**
+ * Iterator valid function
+ * Returns FAILURE or SUCCESS
+ * @param iter
+ * @param tsrm_ls
+ * @return int
+ */
+ static int valid(zend_object_iterator *iter TSRMLS_DC);
+
+ /**
+ * Fetch the current item
+ * @param iter
+ * @param data
+ * @param tsrm_ls
+ */
+ static void current(zend_object_iterator *iter, zval ***data TSRMLS_DC);
+
+ /**
+ * Fetch the key for the current element (optional, may be NULL). The key
+ * should be written into the provided zval* using the ZVAL_* macros. If
+ * this handler is not provided auto-incrementing integer keys will be
+ * used.
+ * @param iter
+ * @param data
+ * @param tsrm_ls
+ */
+ static void key(zend_object_iterator *iter, zval *data TSRMLS_DC);
+
+ /**
+ * Function to retrieve the current key, php 5.3 style
+ * @param iter
+ * @param str_key
+ * @param str_key_len
+ * @param int_key
+ * @param tsrm_ls
+ * @return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG
+ */
+ static int key(zend_object_iterator *iter, char **str_key, unsigned int *str_key_len, unsigned long *int_key TSRMLS_DC);
+
+ /**
+ * Step forwards to the next element
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void next(zend_object_iterator *iter TSRMLS_DC);
+
+ /**
+ * Rewind the iterator back to the start
+ * @param iter
+ * @param tsrm_ls
+ */
+ static void rewind(zend_object_iterator *iter TSRMLS_DC);
+
+public:
+ /**
+ * Constructor
+ * @param iterator The iterator that is implemented by the extension
+ */
+ IteratorImpl(Iterator *iterator) : _iterator(iterator)
+ {
+ // initialize impl object
+ _impl.data = this;
+ _impl.index = 0;
+ _impl.funcs = functions();
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~IteratorImpl() {}
+
+ /**
+ * Internal method that returns the implementation object
+ * @return zend_object_iterator
+ */
+ zend_object_iterator *implementation()
+ {
+ return &_impl;
+ }
+};
+
+/**
+ * End namespace
+ */
+}
diff --git a/src/member.h b/zend/member.h
index 7aa01d8..7aa01d8 100644
--- a/src/member.h
+++ b/zend/member.h
diff --git a/src/members.cpp b/zend/members.cpp
index 1965807..1965807 100644
--- a/src/members.cpp
+++ b/zend/members.cpp
diff --git a/src/method.h b/zend/method.h
index dd18a9a..dd18a9a 100644
--- a/src/method.h
+++ b/zend/method.h
diff --git a/src/namespace.cpp b/zend/namespace.cpp
index d462684..bea31a1 100644
--- a/src/namespace.cpp
+++ b/zend/namespace.cpp
@@ -78,58 +78,55 @@ Namespace &Namespace::add(const char *name, const native_callback_3 &function, c
}
/**
- * Initialize all functions in this namespace
- * @param parent Namespace prefix of the parent
- * @param entries The array to be filled
- * @return int Number of functions that were initialized
+ * Apply a callback to each registered function
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered function.
+ *
+ * @param callback
*/
-size_t Namespace::initialize(const std::string &parent, struct _zend_function_entry entries[])
+void Namespace::apply(const std::function<void(const std::string &ns, Function &func)> &callback)
{
- // keep iterator counter
- int count = 0;
-
- // the namespace to use
- std::string prefix = parent.size() ? parent + "\\" + _name : _name;
-
- // loop through the functions
- for (auto &function : _functions)
- {
- // retrieve entry
- zend_function_entry *entry = &entries[count++];
-
- // let the function fill the entry
- function->initialize(prefix, entry);
- }
+ // loop through the functions, and apply the callback
+ for (auto &function : _functions) callback(_name, *function);
- // loop through the namespace
- for (auto &ns : _namespaces)
- {
- // let the namespace initialize
- count += ns->initialize(prefix, &entries[count]);
- }
-
- // done
- return count;
+ // loop through the other namespaces
+ for (auto &ns : _namespaces) ns->apply([this, callback](const std::string &ns, Function &func) {
+
+ // if this is the root namespace, we don't have to change the prefix
+ if (_name.size() == 0) return callback(ns, func);
+
+ // construct a new prefix
+ // @todo this could be slightly inefficient
+ return callback(_name + "\\" + ns, func);
+ });
}
/**
- * Initialize the namespace after it was registered
- * @param parent Parent namespace
- * @param tsrm_ls
+ * Apply a callback to each registered class
+ *
+ * The callback will be called with the name of the namespace, and
+ * a reference to the registered class.
+ *
+ * @param callback
*/
-void Namespace::initialize(const std::string &parent TSRMLS_DC)
+void Namespace::apply(const std::function<void(const std::string &ns, ClassBase &clss)> &callback)
{
- // the namespace to use
- std::string prefix = parent.size() ? parent + "\\" + _name : _name;
+ // loop through the classes, and apply the callback
+ for (auto &c : _classes) callback(_name, *c);
- // loop through the classes in this namespace
- for (auto &c : _classes) c->implementation()->initialize(c.get(), prefix TSRMLS_CC);
-
- // and loop through the other namespaces
- for (auto &n : _namespaces) n->initialize(prefix TSRMLS_CC);
+ // loop through the other namespaces
+ for (auto &ns : _namespaces) ns->apply([this, callback](const std::string &ns, ClassBase &clss) {
+
+ // if this is the root namespace, we don't have to change the prefix
+ if (_name.size() == 0) return callback(ns, clss);
+
+ // construct a new prefix
+ // @todo this could be slightly inefficient
+ return callback(_name + "\\" + ns, clss);
+ });
}
-
/**
* End namespace
*/
diff --git a/src/notimplemented.h b/zend/notimplemented.h
index ee99254..ee99254 100644
--- a/src/notimplemented.h
+++ b/zend/notimplemented.h
diff --git a/src/nullmember.h b/zend/nullmember.h
index e035897..e035897 100644
--- a/src/nullmember.h
+++ b/zend/nullmember.h
diff --git a/src/numericmember.h b/zend/numericmember.h
index 0a040d3..0a040d3 100644
--- a/src/numericmember.h
+++ b/zend/numericmember.h
diff --git a/src/object.cpp b/zend/object.cpp
index 05449bc..d7fc158 100644
--- a/src/object.cpp
+++ b/zend/object.cpp
@@ -20,7 +20,7 @@ namespace Php {
Object::Object(const char *name, Base *base)
{
// does the object already have a handle?
- if (base->handle())
+ if (base->implementation())
{
// the object is already instantiated, we can assign it the this object
operator=(Value(base));
@@ -36,8 +36,9 @@ Object::Object(const char *name, Base *base)
auto *entry = zend_fetch_class(name, strlen(name), 0 TSRMLS_CC);
if (!entry) throw Php::Exception(std::string("Unknown class name ") + name);
- // store the object in the php object cache (this will give the object a handle)
- base->store(entry TSRMLS_CC);
+ // construct an implementation (this will also set the implementation
+ // member in the base object)
+ new ObjectImpl(entry, base TSRMLS_CC);
// now we can store it
operator=(Value(base));
diff --git a/zend/objectimpl.h b/zend/objectimpl.h
new file mode 100644
index 0000000..f66a6ab
--- /dev/null
+++ b/zend/objectimpl.h
@@ -0,0 +1,207 @@
+/**
+ * ObjectImpl.h
+ *
+ * Implementation class for Base objects that allow the objects to be stored
+ * in the Zend engine
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ObjectImpl
+{
+private:
+ /**
+ * Structure with a first element which is a zend_object, so that
+ * it can be casted to a zend_object
+ * @var MixedObject
+ */
+ struct MixedObject
+ {
+ /**
+ * The actual object is the first member, so that casting
+ * the MixedObject to a zend_object will also result in a valid pointer
+ * @var zend_object
+ */
+ zend_object php;
+
+ /**
+ * Pointer to ourselves
+ * @var ObjectImpl
+ */
+ ObjectImpl *self;
+
+
+ } *_mixed;
+
+ /**
+ * Pointer to the C++ implementation
+ * @var Base
+ */
+ Base *_object;
+
+ /**
+ * The object handle in the Zend engine
+ * @var int
+ */
+ int _handle;
+
+public:
+ /**
+ * Constructor
+ *
+ * This will create a new object in the Zend engine.
+ *
+ * @param entry Zend class entry
+ * @param base C++ object that already exists
+ * @param tsrm_ls Optional threading data
+ */
+ ObjectImpl(zend_class_entry *entry, Base *base TSRMLS_DC)
+ {
+ // allocate a mixed object (for some reason this does not have to deallocated)
+ _mixed = (MixedObject *)emalloc(sizeof(MixedObject));
+
+ // copy properties to the mixed object
+ _mixed->php.ce = entry;
+ _mixed->self = this;
+
+ // store the c++ object
+ _object = base;
+
+ // initialize the object
+ zend_object_std_init(&_mixed->php, entry TSRMLS_CC);
+
+#if PHP_VERSION_ID < 50399
+
+ // tmp variable
+ zval *tmp;
+
+ // initialize the properties, php 5.3 way
+ zend_hash_copy(_mixed->php.properties, &entry->default_properties, (copy_ctor_func_t) zval_property_ctor, &tmp, sizeof(zval*));
+
+#else
+
+ // version higher than 5.3 have an easier way to initialize
+ object_properties_init(&_mixed->php, entry);
+
+#endif
+
+#ifdef ZTS
+
+ // when in thread safety mode, the destruct method and free method have
+ // an extra parameter holding thread information
+ using DestructType = void(zend_object*,unsigned int,void***);
+ using FreeType = void(zend_object*,void***);
+
+#else
+
+ // not in thread mode: no special parameter for the tsrm_ls variable
+ using DestructType = void(zend_object*,unsigned int);
+ using FreeType = void(zend_object*);
+
+#endif
+
+ // store the two destruct methods in temporary vars
+ DestructType *destructMethod = &ClassImpl::destructObject;
+ FreeType *freeMethod = &ClassImpl::freeObject;
+
+ // the destructor and clone handlers are set to NULL. I dont know why, but they do not
+ // seem to be necessary...
+ _handle = zend_objects_store_put(php(), (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);
+
+ // the object may remember that we are its implementation object
+ base->_impl = this;
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~ObjectImpl()
+ {
+ // deallocate the cpp object
+ if (_object) delete _object;
+ }
+
+ /**
+ * Destruct the object
+ * @param tsrm_ls
+ */
+ void destruct(TSRMLS_D)
+ {
+ // pass on to the default destructor
+ zend_objects_free_object_storage(php() TSRMLS_CC);
+
+ // destruct the object
+ delete this;
+ }
+
+ /**
+ * Find the object based on a zval
+ * @param val Zval object
+ * @param tsrm_ls Optional pointer to thread info
+ * @return ObjectImpl
+ */
+ static ObjectImpl *find(zval *val TSRMLS_DC)
+ {
+ // retrieve the old object, which we are going to copy
+ MixedObject *object = (MixedObject *)zend_object_store_get_object(val TSRMLS_CC);
+
+ // done
+ return object->self;
+ }
+
+ /**
+ * Find the object based on a zend_object
+ * @param object Zend object pointer
+ * @return ObjectImpl
+ */
+ static ObjectImpl *find(const zend_object *object)
+ {
+ // retrieve the old object, which we are going to copy
+ const MixedObject *mixed = (MixedObject *)object;
+
+ // done
+ return mixed->self;
+ }
+
+ /**
+ * Retrieve the base class of the original C++ object
+ * @return Base
+ */
+ Base *object()
+ {
+ return _object;
+ }
+
+ /**
+ * Pointer to the PHP object
+ * @return zend_object
+ */
+ zend_object *php()
+ {
+ return &_mixed->php;
+ }
+
+ /**
+ * Retrieve the handle object
+ * @return int
+ */
+ int handle() const
+ {
+ return _handle;
+ }
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/zend/origexception.h b/zend/origexception.h
new file mode 100644
index 0000000..775e412
--- /dev/null
+++ b/zend/origexception.h
@@ -0,0 +1,145 @@
+/**
+ * OrigException.h
+ *
+ * Class that wraps around an exception that was thrown by PHP code,
+ * and that could - but not necessarily has to - be caught by C++
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class OrigException : public Value, public Exception
+{
+private:
+ /**
+ * Is this a an exception that was caught by extension C++ code.
+ *
+ * When the object is initially created, we assume that it will be caught
+ * by C++ code. If it later turns out that the PHP-CPP can catch this
+ * exception after the extension C++ code ran, the variable is set back
+ * to false.
+ *
+ * @var bool
+ */
+ bool _handled = true;
+
+#ifdef ZTS
+ /**
+ * When we run in multi-thread mode, we store the thread handle
+ * @var void***
+ */
+ TSRMLS_D;
+#endif
+
+public:
+ /**
+ * Constructor
+ * @param val
+ */
+ OrigException(zval *val TSRMLS_DC) :
+ Value(val), Exception("OrigException")
+ {
+#ifdef ZTS
+ // copy tsrm_ls
+ this->TSRMLS_C = TSRMLS_C;
+#endif
+ }
+
+ /**
+ * Copy constructor
+ * @param exception
+ */
+ OrigException(const OrigException &exception) :
+ Value(exception), Exception("OrigException"), _handled(exception._handled)
+ {
+#ifdef ZTS
+ // copy tsrm_ls
+ TSRMLS_C = exception.TSRMLS_C;
+#endif
+ }
+
+ /**
+ * Move constructor
+ * @param exception
+ */
+ OrigException(OrigException &&exception) :
+ Value(std::move(exception)), Exception("OrigException"), _handled(exception._handled)
+ {
+ // set other exception to handled so that it wont do anything on destruction
+ exception._handled = true;
+
+#ifdef ZTS
+ // copy tsrm_ls
+ TSRMLS_C = exception.TSRMLS_C;
+#endif
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~OrigException() throw()
+ {
+ // if the exception was not handled by C++ code, we're not going to do anything
+ // and the exception stays active
+ if (!_handled) return;
+
+ // the exception was handled, so we should clean it up
+ zend_clear_exception(TSRMLS_C);
+ }
+
+ /**
+ * This is _not_ a native exception, it was thrown by a PHP script
+ * @return bool
+ */
+ virtual bool native() const override
+ {
+ return false;
+ }
+
+ /**
+ * Reactivate the exception
+ */
+ void reactivate()
+ {
+ // it was not handled by extension C++ code
+ _handled = false;
+ }
+};
+
+/**
+ * Global function to process an exception
+ * @param exception
+ * @param tsrm_ls
+ */
+inline void process(Exception &exception TSRMLS_DC)
+{
+ // is this a native exception?
+ if (exception.native())
+ {
+ // 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
+ {
+ // 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
+ // going to tell to the exception that it is still active
+ OrigException &orig = static_cast<OrigException&>(exception);
+
+ // reactive the exception
+ orig.reactivate();
+ }
+}
+
+/**
+ * End of namespace
+ */
+}
diff --git a/zend/parametersimpl.h b/zend/parametersimpl.h
new file mode 100644
index 0000000..fd14238
--- /dev/null
+++ b/zend/parametersimpl.h
@@ -0,0 +1,53 @@
+/**
+ * ParametersImpl.h
+ *
+ * Extended parameters class that can be instantiated
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2013 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class ParametersImpl : public Parameters
+{
+public:
+ /**
+ * Constructor
+ * @param this_ptr Pointer to the object
+ * @param argc Number of arguments
+ * @param tsrm_ls
+ */
+ ParametersImpl(zval *this_ptr, int argc TSRMLS_DC) : Parameters(this_ptr ? ObjectImpl::find(this_ptr TSRMLS_CC)->object() : nullptr)
+ {
+ // reserve plenty of space
+ reserve(argc);
+
+ // loop through the arguments
+ for (int i=0; i<argc; i++)
+ {
+ // get the argument
+ zval **arg = (zval **) (zend_vm_stack_top(TSRMLS_C) - 1 - (argc-i));
+
+ // append value
+ push_back(Value(*arg));
+ }
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~ParametersImpl() {}
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/src/property.h b/zend/property.h
index f0fd46f..f0fd46f 100644
--- a/src/property.h
+++ b/zend/property.h
diff --git a/zend/streambuf.cpp b/zend/streambuf.cpp
new file mode 100644
index 0000000..86e5f03
--- /dev/null
+++ b/zend/streambuf.cpp
@@ -0,0 +1,55 @@
+/**
+ * StreamBuf.cpp
+ *
+ * Implementation file for the StreamBuf class
+ *
+ * @see http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+#include "includes.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Called when the internal buffer should be synchronized
+ * @return int
+ */
+int StreamBuf::sync()
+{
+ // current buffer size
+ size_t size = pptr() - pbase();
+
+ // is this the error stream or the regular output stream?
+ if (_error)
+ {
+ // write to error (the zend_error() method is a varargs function,
+ // which means that we have to include a printf() like format as first
+ // parameter. We can not specify pbase() directly, because (1) it is
+ // not null terminated and (2) it could contain % signs and allow all
+ // sorts of buffer overflows.
+ zend_error(_error, "%.*s", (int)size, pbase());
+
+ }
+ else
+ {
+ // write to zend
+ zend_write(pbase(), size);
+ }
+
+ // reset the buffer
+ pbump(-size);
+
+ // done
+ return 0;
+}
+
+/**
+ * End namespace
+ */
+}
+ \ No newline at end of file
diff --git a/src/streams.cpp b/zend/streams.cpp
index ba6d916..ba6d916 100644
--- a/src/streams.cpp
+++ b/zend/streams.cpp
diff --git a/src/stringmember.h b/zend/stringmember.h
index e58cd3d..e58cd3d 100644
--- a/src/stringmember.h
+++ b/zend/stringmember.h
diff --git a/src/super.cpp b/zend/super.cpp
index 506d4a5..506d4a5 100644
--- a/src/super.cpp
+++ b/zend/super.cpp
diff --git a/src/traverseiterator.h b/zend/traverseiterator.h
index 84c50f0..16f1ce7 100644
--- a/src/traverseiterator.h
+++ b/zend/traverseiterator.h
@@ -17,7 +17,7 @@ namespace Php {
/**
* Class definition
*/
-class TraverseIterator : public IteratorImpl
+class TraverseIterator : public ValueIteratorImpl
{
public:
/**
@@ -73,9 +73,9 @@ public:
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl*
+ * @return ValueIteratorImpl*
*/
- virtual IteratorImpl *clone() override
+ virtual ValueIteratorImpl *clone() override
{
// we need the tsrm_ls variable
TSRMLS_FETCH();
@@ -119,7 +119,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const override
+ virtual bool equals(const ValueIteratorImpl *that) const override
{
// of course if the objects are identical
if (this == that) return true;
diff --git a/src/value.cpp b/zend/value.cpp
index 6684bd0..2ca1585 100644
--- a/src/value.cpp
+++ b/zend/value.cpp
@@ -177,22 +177,22 @@ Value::Value(const Base *object)
{
// there are two options: the object was constructed from user space,
// and is already linked to a handle, or it was constructed from C++
- // space, and no handle does yet exist
- int handle = object->handle();
+ // space, and no handle does yet exist, find the implementation object
+ auto *impl = object->implementation();
// do we have a handle?
- if (!handle) throw Php::Exception("Assigning an unassigned object to a variable");
+ if (!impl) throw Php::Exception("Assigning an unassigned object to a variable");
// make a regular zval, and set it to an object
MAKE_STD_ZVAL(_val);
Z_TYPE_P(_val) = IS_OBJECT;
- Z_OBJ_HANDLE_P(_val) = handle;
+ Z_OBJ_HANDLE_P(_val) = impl->handle();
// we need the tsrm_ls variable
TSRMLS_FETCH();
// we have to lookup the object in the object-table
- zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[handle];
+ zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[impl->handle()];
// this is copy-pasted from zend_objects.c - and it is necessary too!
if (!obj_bucket->bucket.obj.handlers) obj_bucket->bucket.obj.handlers = &std_object_handlers;
@@ -1257,7 +1257,7 @@ static Value do_exec(zval **object, zval *method, int argc, zval ***params)
{
// was an exception thrown inside the function? 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));
+ if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC);
// no (additional) exception was thrown
return retval ? Value(retval) : nullptr;
@@ -1890,11 +1890,7 @@ Base *Value::implementation() const
TSRMLS_FETCH();
// retrieve the mixed object that contains the base
- MixedObject *object = (MixedObject *)zend_object_store_get_object(_val TSRMLS_CC);
- if (!object) return nullptr;
-
- // retrieve the associated C++ class
- return object->cpp;
+ return ObjectImpl::find(_val TSRMLS_CC)->object();
}
/**
diff --git a/src/valueiterator.cpp b/zend/valueiterator.cpp
index 65c687c..65c687c 100644
--- a/src/valueiterator.cpp
+++ b/zend/valueiterator.cpp
diff --git a/src/iteratorimpl.h b/zend/valueiteratorimpl.h
index babf9f0..82c888d 100644
--- a/src/iteratorimpl.h
+++ b/zend/valueiteratorimpl.h
@@ -1,9 +1,9 @@
/**
- * IteratorImpl.h
+ * ValueIteratorImpl.h
*
- * Interface that describes what an implementation of an iterator should
+ * Interface that describes what an implementation of a value iterator should
* look like. This is an internal class that extension developers do not
- * need.
+ * need. It is used internally inside the ValueIterator class.
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2014 Copernica BV
@@ -17,25 +17,25 @@ namespace Php {
/**
* Class definition
*/
-class IteratorImpl
+class ValueIteratorImpl
{
public:
/**
* Constructor
*/
- IteratorImpl() {}
+ ValueIteratorImpl() {}
/**
* Destructor
*/
- virtual ~IteratorImpl() {}
+ virtual ~ValueIteratorImpl() {}
/**
* Clone the object
* @param tsrm_ls
- * @return IteratorImpl*
+ * @return ValueIteratorImpl*
*/
- virtual IteratorImpl *clone() = 0;
+ virtual ValueIteratorImpl *clone() = 0;
/**
* Increment position (pre-increment)
@@ -55,7 +55,7 @@ public:
* @param that
* @return bool
*/
- virtual bool equals(const IteratorImpl *that) const = 0;
+ virtual bool equals(const ValueIteratorImpl *that) const = 0;
/**
* Derefecence, this returns a std::pair with the current key and value