summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-02 23:28:10 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-03-02 23:28:10 +0100
commit8f24af4c28e74ef1769aef6ab00c480e09be7453 (patch)
treec73b7de11abbdd8ed2d3f3fa5b63fdd2a1409cb8
parentf7dcf5d81fa1e43533c786d9443e5222398dc8b9 (diff)
work in progress to support implementing SPL interfaces, disabled the _self variable in Php::Base because by having each object keeping a reference to itself, the refcounter never reached zero and the object was thus never destructed, checking if we can get a new implementation one way or another
-rw-r--r--Examples/CppClassesInPhp/cppclassinphp.cpp19
-rw-r--r--include/base.h108
-rw-r--r--include/class.h27
-rw-r--r--include/classbase.h32
-rw-r--r--include/countable.h45
-rw-r--r--include/hashmember.h4
-rw-r--r--phpcpp.h1
-rw-r--r--src/classbase.cpp5
-rw-r--r--src/countable.cpp32
-rw-r--r--src/includes.h1
10 files changed, 184 insertions, 90 deletions
diff --git a/Examples/CppClassesInPhp/cppclassinphp.cpp b/Examples/CppClassesInPhp/cppclassinphp.cpp
index 70233c9..7ef4d12 100644
--- a/Examples/CppClassesInPhp/cppclassinphp.cpp
+++ b/Examples/CppClassesInPhp/cppclassinphp.cpp
@@ -11,7 +11,7 @@
*/
using namespace std;
-class MyCustomClass : public Php::Base
+class MyCustomClass : public Php::Base // , public Php::Countable
{
private:
int _x;
@@ -39,6 +39,11 @@ public:
std::cout << "MyCustomClass::__destruct" << std::endl;
}
+ virtual Php::Value count() //override
+ {
+ return 33;
+ }
+
void myMethod(Php::Parameters &params)
{
// check number of parameters
@@ -47,12 +52,12 @@ public:
std::cout << "myMethod is called." << std::endl;
_x = params[0];
- std::cout << "get property1 " << value()["property1"] << std::endl;
-
- // set it to something else
- value().set("property1", "new value");
-
- std::cout << "get property1 " << value()["property1"] << std::endl;
+ // std::cout << "get property1 " << value()["property1"] << std::endl;
+ //
+ // // set it to something else
+ // value().set("property1", "new value");
+ //
+ // std::cout << "get property1 " << value()["property1"] << std::endl;
}
};
diff --git a/include/base.h b/include/base.h
index 7d7be98..46f5678 100644
--- a/include/base.h
+++ b/include/base.h
@@ -22,6 +22,11 @@ protected:
Base() {}
public:
+
+ // @todo should we delete the copy and move operators because we do not
+ // allow the CPP code to make copies of itself?
+
+
/**
* Virtual destructor
*/
@@ -31,122 +36,95 @@ public:
* Convert the object to a Php::Value object (how it is used externally)
* @return Object
*/
- Object &value()
- {
- return _self;
- }
+// Object value();
/**
* Convert the object to a Php::Value object (how it is used externally)
* @return Object
*/
- const Object &value() const
- {
- return _self;
- }
+// Object value() const;
/**
* Get access to a property by name using the [] operator
* @param string
- * @return Value
+ * @return HashMember
*/
- Value operator[](const char *name)
- {
- return _self[name];
- }
+// HashMember<std::string> operator[](const char *name)
+// {
+// return value()[name];
+// }
/**
* Alternative way to access a property using the [] operator
* @param string
- * @return Value
+ * @return HashMember
*/
- Value operator[](const std::string &name)
- {
- return _self[name];
- }
+// HashMember<std::string> operator[](const std::string &name)
+// {
+// return value()[name];
+// }
/**
* Retrieve a property by name
* @param string
- * @return Value
+ * @return HashMember
*/
- Value property(const char *name)
- {
- return _self[name];
- }
+// HashMember<std::string> property(const char *name)
+// {
+// return value()[name];
+// }
/**
* Retrieve a property by name
* @param string
- * @return Value
+ * @return HashMember
*/
- Value property(const std::string &name)
- {
- return _self[name];
- }
+// HashMember<std::string> property(const std::string &name)
+// {
+// return value()[name];
+// }
/**
* Get access to a property by name using the [] operator
* @param string
* @return Value
*/
- Value operator[](const char *name) const
- {
- return _self[name];
- }
+// Value operator[](const char *name) const
+// {
+// return value()[name];
+// }
/**
* Alternative way to access a property using the [] operator
* @param string
* @return Value
*/
- Value operator[](const std::string &name) const
- {
- return _self[name];
- }
+// Value operator[](const std::string &name) const
+// {
+// return value()[name];
+// }
/**
* Retrieve a property by name
* @param string
* @return Value
*/
- Value property(const char *name) const
- {
- return _self[name];
- }
+// Value property(const char *name) const
+// {
+// return value()[name];
+// }
/**
* Retrieve a property by name
* @param string
* @return Value
*/
- Value property(const std::string &name) const
- {
- return _self[name];
- }
+// Value property(const std::string &name) const
+// {
+// return value()[name];
+// }
-protected:
- /**
- * The zend_object
- * @var Value
- */
- Object _self;
-
private:
- /**
- * Private method to assign the zend object
- * @param zend_object
- */
- void assign(Value &&object)
- {
- // copy pointer
- _self = std::move(object);
- }
-
- /**
- * ClassBase has access to private data
- */
- friend class ClassBase;
};
diff --git a/include/class.h b/include/class.h
index 851de8d..8bfcad4 100644
--- a/include/class.h
+++ b/include/class.h
@@ -16,11 +16,6 @@
*/
/**
- * Forward declarations
- */
-struct _zend_class_entry;
-
-/**
* Set up namespace
*/
namespace Php {
@@ -40,7 +35,11 @@ public:
*
* @param name Name of the class
*/
- Class(const char *name) : ClassBase(name) {}
+ Class(const char *name) : ClassBase(name)
+ {
+ // check for special classes
+ if (std::is_base_of<Countable, T>::value) ClassBase::interface(Countable::implementation());
+ }
/**
* Copy constructor
@@ -74,14 +73,14 @@ public:
* @param flags Optional flags
* @param args Argument descriptions
*/
- void method(const char *name, void(T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), flags, args); }
- void method(const char *name, void(T::*method)(Parameters &params), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), flags, args); }
- void method(const char *name, bool(T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), flags, args); }
- void method(const char *name, bool(T::*method)(Parameters &params), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), flags, args); }
- void method(const char *name, void(T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), Public, args); }
- void method(const char *name, void(T::*method)(Parameters &params), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), Public, args); }
- void method(const char *name, bool(T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), Public, args); }
- void method(const char *name, bool(T::*method)(Parameters &params), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), Public, args); }
+ void method(const char *name, void (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), flags, args); }
+ void method(const char *name, void (T::*method)(Parameters &params), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), flags, args); }
+ void method(const char *name, Value (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), flags, args); }
+ void method(const char *name, Value (T::*method)(Parameters &params), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), flags, args); }
+ void method(const char *name, void (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_0>(method), Public, args); }
+ void method(const char *name, void (T::*method)(Parameters &params), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_1>(method), Public, args); }
+ void method(const char *name, Value (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_2>(method), Public, args); }
+ void method(const char *name, Value (T::*method)(Parameters &params), const Arguments &args = {}) { ClassBase::method(name, static_cast<method_callback_3>(method), Public, args); }
/**
* Add an abstract method to the class
diff --git a/include/classbase.h b/include/classbase.h
index baa1624..e23c579 100644
--- a/include/classbase.h
+++ b/include/classbase.h
@@ -85,14 +85,15 @@ public:
* @param value
* @return Base
*/
- Base* construct(Value &&value)
+ Base* construct(const struct _zend_object_value &value)
{
// construct the base
auto *result = construct();
if (!result) return nullptr;
// assign the zend object to it
- result->assign(std::move(value));
+ // @todo fix this
+// result->assign(value);
// done
return result;
@@ -170,6 +171,27 @@ protected:
void property(const char *name, const char *value, int flags = Php::Public);
void property(const char *name, double value, int flags = Php::Public);
+ /**
+ * Add an implemented interface
+ *
+ * This can only be used to register interfaces that are already defined
+ * by Zend, and not for user space interface or custom extension interfaces.
+ * This is probably not so much of a problem, as this feature is mostly
+ * useful for interfaces like 'Countable', 'ArrayAccess', 'Iterator', et
+ * cetera. Interfaces defined in user space are in normal operations
+ * inaccessible (user space code normally runs after the extension has been
+ * set up) - so we do not need a feature to set these.
+ *
+ * It does however make sense to support implementing extension-specific
+ * interface. We may add this feature in the future.
+ *
+ * @param interface
+ */
+ void interface(struct _zend_class_entry *interface)
+ {
+ // register the interface
+ _interfaces.push_back(interface);
+ }
private:
/**
@@ -224,6 +246,12 @@ private:
*/
std::list<std::shared_ptr<Member>> _members;
+ /**
+ * All interfaces that are implemented
+ * @var std::list
+ */
+ std::list<struct _zend_class_entry*> _interfaces;
+
};
/**
diff --git a/include/countable.h b/include/countable.h
new file mode 100644
index 0000000..12d87d5
--- /dev/null
+++ b/include/countable.h
@@ -0,0 +1,45 @@
+/**
+ * Countable.h
+ *
+ * "Interface" that can be "implemented" by your class. If you do, you
+ * create your class like this:
+ *
+ * class MyClass : public Php::Base, public Php::Countable { ... }
+ *
+ * You will have to implement the count() method, which should return the
+ * number of elements in the class
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class Countable
+{
+public:
+ /**
+ * Implementation of the countable interface
+ * @return zend_class_entry*
+ * @internal
+ */
+ static struct _zend_class_entry *implementation();
+
+ /**
+ * Retrieve the number of items in the class
+ * @return Value
+ */
+ virtual Value count() = 0;
+};
+
+/**
+ * End namespace
+ */
+}
+
diff --git a/include/hashmember.h b/include/hashmember.h
index a61865c..9933445 100644
--- a/include/hashmember.h
+++ b/include/hashmember.h
@@ -350,6 +350,8 @@ private:
*/
HashMember(const Value *base, Type index) : _base(*base), _index(index) {}
+ // @todo add move constructor
+
/**
* Protected copy constructor
* @param value Other element
@@ -389,7 +391,7 @@ private:
* Only value objects may construct members
*/
friend class Value;
- friend class Properties;
+ friend class Base;
};
diff --git a/phpcpp.h b/phpcpp.h
index b7680ca..d913cc6 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -38,6 +38,7 @@
#include <phpcpp/parameters.h>
#include <phpcpp/modifiers.h>
#include <phpcpp/base.h>
+#include <phpcpp/countable.h>
#include <phpcpp/classtype.h>
#include <phpcpp/classbase.h>
#include <phpcpp/class.h>
diff --git a/src/classbase.cpp b/src/classbase.cpp
index 87a1cd2..c7ade6c 100644
--- a/src/classbase.cpp
+++ b/src/classbase.cpp
@@ -101,7 +101,7 @@ static zend_object_value create_object(zend_class_entry *type TSRMLS_DC)
result.handle = zend_objects_store_put(object, NULL, deallocate_object, clone_object TSRMLS_CC);
// finally, construct the cpp object
- object->cpp = info->construct(Value(result));
+ object->cpp = info->construct(result);
// done
return result;
@@ -215,6 +215,9 @@ void ClassBase::initialize(const std::string &prefix)
// set access types flags for class
_entry->ce_flags = (int)_type;
+ // mark the interfaces as being implemented
+ for (auto &interface : _interfaces) zend_do_implement_interface(_entry, interface);
+
// declare all member variables
for (auto &member : _members) member->initialize(_entry);
}
diff --git a/src/countable.cpp b/src/countable.cpp
new file mode 100644
index 0000000..6182afd
--- /dev/null
+++ b/src/countable.cpp
@@ -0,0 +1,32 @@
+/**
+ * Countable.cpp
+ *
+ * Implementation of the Countable interface
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+#include "includes.h"
+
+#include "spl/spl_iterators.h"
+
+/**
+ * Set up namespace
+ */
+namespace Php {
+
+/**
+ * Implementation of the countable interface
+ * @return zend_class_entry*
+ * @internal
+ */
+struct _zend_class_entry *Countable::implementation()
+{
+ return spl_ce_Countable;
+}
+
+/**
+ * End namespace
+ */
+}
+
diff --git a/src/includes.h b/src/includes.h
index 81370bc..59ee8b3 100644
--- a/src/includes.h
+++ b/src/includes.h
@@ -57,6 +57,7 @@
#include "../include/parameters.h"
#include "../include/modifiers.h"
#include "../include/base.h"
+#include "../include/countable.h"
#include "../include/classtype.h"
#include "../include/classbase.h"
#include "../include/class.h"