Skip to content

[pull] master from CopernicaMarketingSoftware:master #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ INSTALL_LIB = ${INSTALL_PREFIX}/lib
#

SONAME = 2.3
VERSION = 2.3.4
VERSION = 2.3.5


#
Expand Down
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