Skip to content

Commit

Permalink
Merge pull request #494 from brammel123/master
Browse files Browse the repository at this point in the history
when the Serializable interface is implemented, automatically also define the "serialize" and "unserialize" methods
  • Loading branch information
EmielBruijntjes authored Jun 29, 2022
2 parents 7a2212b + 8984634 commit ae45138
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
*.a.*
*.so.*
shared/
static/
static/
.vscode/
18 changes: 17 additions & 1 deletion include/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Base class for defining your own objects
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2013 Copernica BV
* @copyright 2013 - 2022 Copernica BV
*/

/**
Expand Down Expand Up @@ -261,6 +261,22 @@ class PHPCPP_EXPORT Base
*/
int __compare(const Base &base) const;

/**
* Method that is called when an explicit call to $object->serialize() is made
* Note that a call to serialize($object) does not end up in this function, but
* is handled by the user-space implementation of Serializable::serialize()).
* @return Php::Value
*/
Php::Value __serialize();

/**
* Method that is called when an explicit call to $object->unserialize() is made
* Note that a call to unserialize($string) does not end up in this function, but
* is handled by the user-space implementation of Serializable::unserialize()).
* @param params The passed parameters
*/
void __unserialize(Php::Parameters &params);


private:
/**
Expand Down
47 changes: 46 additions & 1 deletion zend/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* Implementation file for the base of all classes
*
* @copyright 2014 Copernica BV
* @copyright 2014 - 2022 Copernica BV
*/
#include "includes.h"

Expand Down Expand Up @@ -217,6 +217,51 @@ int Base::__compare(const Base &that) const
return 1;
}

/**
* Method that is called when an explicit call to $object->serialize() is made
* Note that a call to serialize($object) does not end up in this function, but
* is handled by the user-space implementation of Serializable::serialize()).
* @return Php::Value
*/
Php::Value Base::__serialize()
{
// 'this' refers to a Php::Base class, but we expect that is also implements the Serializable
// interface (otherwise we would never have registered the __serialize function as a callback)
auto *serializable = dynamic_cast<Serializable*>(this);

// this one should not fail
if (serializable == nullptr) return "";

// pass the call to the interface
return serializable->serialize();
}

/**
* Method that is called when an explicit call to $object->unserialize() is made
* Note that a call to unserialize($string) does not end up in this function, but
* is handled by the user-space implementation of Serializable::unserialize()).
* @param params The passed parameters
*/
void Base::__unserialize(Php::Parameters &params)
{
// 'this' refers to a Php::Base class, but we expect that is also implements the Serializable
// interface (otherwise we would never have registered the __serialize function as a callback)
auto *serializable = dynamic_cast<Serializable*>(this);

// this one should not fail
if (serializable == nullptr) return;

// the passed in parameter
Php::Value param = params[0];

// make sure the parameter is indeed a string
param.setType(Type::String);

// pass the call to the interface
serializable->unserialize(param.rawValue(), param.size());
}


/**
* End namespace
*/
Expand Down
5 changes: 5 additions & 0 deletions zend/callable.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ class Callable
*/
void initialize(zend_internal_function_info *info, const char *classname = nullptr) const;

/**
* Name of the function
* @return const std::string&
*/
const std::string &name() const { return _name; }

protected:

Expand Down
40 changes: 39 additions & 1 deletion zend/classimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
#include "includes.h"
#include <cstring>
#include <algorithm>

/**
* Set up namespace
Expand Down Expand Up @@ -1300,6 +1301,19 @@ int ClassImpl::unserialize(zval *object, zend_class_entry *entry, const unsigned
return SUCCESS;
}

/**
* Helper method to check if a function is registered for this instance
* @param name name of the function to check for
* @return bool Wether the function exists or not
*/
bool ClassImpl::hasMethod(const char* name) const
{
// find the method
auto result = std::find_if(_methods.begin(), _methods.end(), [name](std::shared_ptr<Method> method){ return method->name() == name; });
// return wether its found or not
return result != _methods.end();
}

/**
* Retrieve an array of zend_function_entry objects that hold the
* properties for each method. This method is called at extension
Expand All @@ -1313,8 +1327,19 @@ const struct _zend_function_entry *ClassImpl::entries()
// already initialized?
if (_entries) return _entries;

// the number of entries that need to be allocated
size_t entrycount = _methods.size();

// if the class is serializable, we might need some extra methods
if (_base->serializable())
{
// add the serialize method if the class does not have one defined yet
if (!hasMethod("serialize")) entrycount += 1;
if (!hasMethod("unserialize")) entrycount += 1;
}

// allocate memory for the functions
_entries = new zend_function_entry[_methods.size() + 1];
_entries = new zend_function_entry[entrycount + 1];

// keep iterator counter
int i = 0;
Expand All @@ -1329,6 +1354,19 @@ const struct _zend_function_entry *ClassImpl::entries()
method->initialize(entry, _name);
}

// if the class is serializable, we might need some extra methods
if (_base->serializable())
{
// the method objectneed to stay in scope for the lifetime of the script (because the register a pointer
// to an internal string buffer) -- so we create them as static variables
static Method serialize("serialize", &Base::__serialize, 0, {});
static Method unserialize("unserialize", &Base::__unserialize, 0, { ByVal("input", Type::Undefined, true) });

// register the serialize and unserialize method in case this was not yet done in PHP user space
if (!hasMethod("serialize")) serialize.initialize(&_entries[i++], _name);
if (!hasMethod("unserialize")) unserialize.initialize(&_entries[i++], _name);
}

// last entry should be set to all zeros
zend_function_entry *last = &_entries[i];

Expand Down
7 changes: 7 additions & 0 deletions zend/classimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ class ClassImpl
*/
const zend_function_entry *entries();

/**
* Helper method to check if a function is registered for this instance
* @param name name of the function to check for
* @return bool Wether the function exists or not
*/
bool hasMethod(const char* name) const;

/**
* Helper method to turn a property into a zval
*
Expand Down

0 comments on commit ae45138

Please sign in to comment.