From 8f24af4c28e74ef1769aef6ab00c480e09be7453 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Sun, 2 Mar 2014 23:28:10 +0100 Subject: 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 --- Examples/CppClassesInPhp/cppclassinphp.cpp | 19 +++-- include/base.h | 108 ++++++++++++----------------- include/class.h | 27 ++++---- include/classbase.h | 32 ++++++++- include/countable.h | 45 ++++++++++++ include/hashmember.h | 4 +- phpcpp.h | 1 + src/classbase.cpp | 5 +- src/countable.cpp | 32 +++++++++ src/includes.h | 1 + 10 files changed, 184 insertions(+), 90 deletions(-) create mode 100644 include/countable.h create mode 100644 src/countable.cpp 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 ¶ms) { // 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 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 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 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 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 @@ -15,11 +15,6 @@ * @copyright 2013, 2014 Copernica BV */ -/** - * Forward declarations - */ -struct _zend_class_entry; - /** * Set up namespace */ @@ -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::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), flags, args); } - void method(const char *name, void(T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } - void method(const char *name, bool(T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } - void method(const char *name, bool(T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } - void method(const char *name, void(T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } - void method(const char *name, void(T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } - void method(const char *name, bool(T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } - void method(const char *name, bool(T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } + void method(const char *name, void (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } + void method(const char *name, void (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } + void method(const char *name, Value (T::*method)(), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } + void method(const char *name, Value (T::*method)(Parameters ¶ms), int flags, const Arguments &args = {}) { ClassBase::method(name, static_cast(method), flags, args); } + void method(const char *name, void (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } + void method(const char *name, void (T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } + void method(const char *name, Value (T::*method)(), const Arguments &args = {}) { ClassBase::method(name, static_cast(method), Public, args); } + void method(const char *name, Value (T::*method)(Parameters ¶ms), const Arguments &args = {}) { ClassBase::method(name, static_cast(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> _members; + /** + * All interfaces that are implemented + * @var std::list + */ + std::list _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 + * @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 #include #include +#include #include #include #include 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 + * @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" -- cgit v1.2.3