diff --git a/CMakeLists.txt b/CMakeLists.txt index be97069f..2e1528e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,6 +190,7 @@ SET(PHPCPP_HEADERS_INCLUDE include/argument.h include/array.h include/arrayaccess.h + include/propertyptrptr.h include/base.h include/byref.h include/byval.h diff --git a/include/propertyptrptr.h b/include/propertyptrptr.h new file mode 100644 index 00000000..d72fc018 --- /dev/null +++ b/include/propertyptrptr.h @@ -0,0 +1,41 @@ +/** + * PropertyPtrPtr.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::PropertyPtrPtr { ... } + * + * @author Kirill Morozov + * @copyright 2020 Morozov + */ + +/** + * Set up namespace + */ +namespace Php { + +/** + * Class definition + */ +class PHPCPP_EXPORT PropertyPtrPtr +{ +public: + + /** + * Retrieve a member + * @param key + * @return value + */ + virtual Php::Value getPropertyPtrPtr(const Php::Value &member, int type) = 0; + + /** + * Destructor + */ + virtual ~PropertyPtrPtr() = default; +}; + +/** + * End namespace + */ +} diff --git a/phpcpp.h b/phpcpp.h index 1b0da150..8ab55d14 100644 --- a/phpcpp.h +++ b/phpcpp.h @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/zend/classimpl.cpp b/zend/classimpl.cpp index 6ff96c02..904e3192 100644 --- a/zend/classimpl.cpp +++ b/zend/classimpl.cpp @@ -360,6 +360,8 @@ zend_object_handlers *ClassImpl::objectHandlers() _handlers.has_property = &ClassImpl::hasProperty; _handlers.unset_property = &ClassImpl::unsetProperty; + _handlers.get_property_ptr_ptr = &ClassImpl::getPropertyPtrPtr; + // when a method is called (__call and __invoke) _handlers.get_method = &ClassImpl::getMethod; _handlers.get_closure = &ClassImpl::getClosure; @@ -651,6 +653,46 @@ zval *ClassImpl::readDimension(zval *object, zval *offset, int type, zval *rv) return std_object_handlers.read_dimension(object, offset, type, rv); } } +/** + * Function that is called when the object property is used for write operations in PHP + * + * This is the object->property[x]=y operation in PHP, and mapped to the getPropertyPtrPtr() method + * of the ArrayAccess PropertyPtrPtr + * + * @param object The object on which it is called + * @param member The name of the property + * @param type The type of operation 0 - read, 1 - write + * @return zval* + */ +zval *ClassImpl::getPropertyPtrPtr(zval *object, zval *member, int type, void **cache_slot) +{ + PropertyPtrPtr *p_ptr_ptr = dynamic_cast(ObjectImpl::find(object)->object()); + if (p_ptr_ptr) + { + try + { + Php::Value res = p_ptr_ptr->getPropertyPtrPtr(member, type); + return res.detach(true); + } + catch (Throwable &throwable) + { + // object was not caught by the extension, let it end up in user space + throwable.rethrow(); + + // unreachable + return Value(nullptr).detach(false); + } + + } + else + { + // ArrayAccess not implemented, check if there is a default handler + if (!std_object_handlers.get_property_ptr_ptr) return nullptr; + + // call default + return std_object_handlers.get_property_ptr_ptr(object, member, type, cache_slot); + } +} /** * Function that is called when the object is used as an array in PHP diff --git a/zend/classimpl.h b/zend/classimpl.h index 225c3ad7..f654bc1d 100644 --- a/zend/classimpl.h +++ b/zend/classimpl.h @@ -235,6 +235,8 @@ class ClassImpl */ static zend_object_handlers *objectHandlers(zend_class_entry *entry); + static zval *getPropertyPtrPtr(zval *object, zval *member, int type, void **cache_slot); + /** * Function to create a new iterator to iterate over an object * @param entry The class entry diff --git a/zend/includes.h b/zend/includes.h index fd914611..5a60e20b 100644 --- a/zend/includes.h +++ b/zend/includes.h @@ -90,6 +90,7 @@ #include "../include/base.h" #include "../include/countable.h" #include "../include/arrayaccess.h" +#include "../include/propertyptrptr.h" #include "../include/serializable.h" #include "../include/iterator.h" #include "../include/traversable.h"