Skip to content
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

Add PHP 8.1 Support #497

Merged
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
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ php:
- 7.1
- 7.2
- 7.3
- nightly # doesn't work yet on PHP 7.4! not building.
- 7.4
- 8.0
- nightly


# setting the env is the easiest, because it will mix with all the separate php versions (travis does this)
Expand Down
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
8 changes: 8 additions & 0 deletions include/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ class PHPCPP_EXPORT Base
*/
void __unserialize(Php::Parameters &params);

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


private:
/**
Expand Down
10 changes: 10 additions & 0 deletions include/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,16 @@ class PHPCPP_EXPORT Class : private ClassBase
return std::is_base_of<Serializable,T>::value;
}

/**
* Is this a countable class?
* @return bool
*/
virtual bool countable() const override
{
// check if the templated class overrides from the Countable class
return std::is_base_of<Countable,T>::value;
}

/**
* Call the __clone method
* @param base
Expand Down
1 change: 1 addition & 0 deletions include/classbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class PHPCPP_EXPORT ClassBase
*/
virtual bool traversable() const { return false; }
virtual bool serializable() const { return false; }
virtual bool countable() const { return false; }
virtual bool clonable() const { return false; }

/**
Expand Down
9 changes: 9 additions & 0 deletions include/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ class PHPCPP_EXPORT File
*/
File(const char *name) : File(name, ::strlen(name)) {}

/**
* Alternative constructor with zend_string filename
* and size of the string
*
* @param name the filename
* @param size size of the filename
*/
File(const _zend_string *name, size_t size);

/**
* Alternative constructor with a string object
* @param name the filename
Expand Down
18 changes: 18 additions & 0 deletions zend/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,24 @@ void Base::__unserialize(Php::Parameters &params)
serializable->unserialize(param.rawValue(), param.size());
}

/**
* Method that is called when an explicit call to $object->count() 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::count()).
* @param params The passed parameters
*/
Php::Value Base::__count(Php::Parameters &params)
{
// 'this' refers to a Php::Base class, but we expect that is also implements the Countable
// interface (otherwise we would never have registered the __count function as a callback)
auto *countable = dynamic_cast<Countable*>(this);

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

// pass the call to the interface
return countable->count();
}

/**
* End namespace
Expand Down
20 changes: 17 additions & 3 deletions zend/callable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
#else
// Sanity check
assert(info[argc].type != 0 && info[argc].name == nullptr);

// the callable we are retrieving
#if PHP_VERSION_ID < 80000
Callable *callable = reinterpret_cast<Callable*>(info[argc].type);
#else
Callable *callable = reinterpret_cast<Callable*>(info[argc].type.ptr);
#endif
#endif

// check if sufficient parameters were passed (for some reason this check
Expand Down Expand Up @@ -99,10 +102,10 @@ void Callable::initialize(zend_function_entry *entry, const char *classname, int
_argv[_argc + 1].class_name = reinterpret_cast<const char*>(this);
#else
// @todo this is broken. the zend engine, from 7.2 onwards copies over
// the struct and slices of the last element, because the num_args
// the struct and slices off the last element, because the num_args
// is incorrect in their view. another place to put this may be
// hiding it behind the fname
_argv[_argc + 1].type = reinterpret_cast<zend_type>(this);
_argv[_argc + 1].type = ZEND_TYPE_INIT_PTR(this, IS_PTR, true, 0);
#endif

// we use our own invoke method, which does a lookup
Expand All @@ -129,8 +132,10 @@ void Callable::initialize(zend_internal_function_info *info, const char *classna
{
// initialize all common elements
info->required_num_args = _required;
#if PHP_VERSION_ID < 80000
info->return_reference = false;
info->_is_variadic = false;
#endif

// the structure has been slightly altered since php7.2
#if PHP_VERSION_ID < 70200
Expand All @@ -147,9 +152,18 @@ void Callable::initialize(zend_internal_function_info *info, const char *classna
#else
// the properties that are available on php 7.2 and higher
info->required_num_args = _required;
#if PHP_VERSION_ID < 80000
info->return_reference = false;
info->_is_variadic = false;
info->type = ZEND_TYPE_ENCODE((int)_return, true);
#else
if ((int)_return) {
info->type = (zend_type)ZEND_TYPE_INIT_CODE((int)_return, true, 0);
} else {
info->type = (zend_type)ZEND_TYPE_INIT_NONE(0);
}

#endif
#endif
}

Expand Down
28 changes: 25 additions & 3 deletions zend/callable.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,14 @@ class Callable

// initialize all elements to null
_argv[i].name = nullptr;
#if PHP_VERSION_ID < 80000
_argv[i].is_variadic = false;
_argv[i].pass_by_reference = false;

#endif
// initialize the extra argument prior to 7.2
#if PHP_VERSION_ID < 70200
_argv[i].class_name = nullptr;
#else
#elif PHP_VERSION_ID < 80000
_argv[i].type = 0;
#endif
}
Expand Down Expand Up @@ -203,6 +204,26 @@ class Callable
case Type::Object: info->type_hint = IS_OBJECT; break; // must be an object of the given classname
case Type::Callable: info->type_hint = IS_CALLABLE; break; // anything that can be invoked
default: info->type_hint = IS_UNDEF; break; // if not specified we allow anything
#elif PHP_VERSION_ID >= 80000
case Type::Undefined: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_UNDEF, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // undefined means we'll accept any type
case Type::Null: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_UNDEF, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // this is likely an error, what good would accepting NULL be? accept anything
case Type::False: info->type = (zend_type) ZEND_TYPE_INIT_CODE(_IS_BOOL, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // accept true as well ;)
case Type::True: info->type = (zend_type) ZEND_TYPE_INIT_CODE(_IS_BOOL, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // accept false as well
case Type::Bool: info->type = (zend_type) ZEND_TYPE_INIT_CODE(_IS_BOOL, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // any bool will do, true, false, the options are limitless
case Type::Numeric: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // accept integers here
case Type::Float: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_DOUBLE, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // floating-point values welcome too
case Type::String: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_STRING, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // accept strings, should auto-cast objects with __toString as well
case Type::Array: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_ARRAY, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // array of anything (individual members cannot be restricted)
case Type::Object:
if (arg.classname()) {
info->type = (zend_type) ZEND_TYPE_INIT_CLASS(arg.encoded(), arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0));
break;
}
info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_OBJECT, arg.allowNull(), _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0));
break;
case Type::Callable: info->type = (zend_type) ZEND_TYPE_INIT_CODE(IS_CALLABLE, arg.allowNull(), 0); break; // anything that can be invoke

default: info->type = ZEND_TYPE_INIT_CODE(IS_UNDEF, 0, _ZEND_ARG_INFO_FLAGS(arg.byReference(), 0, 0)); break; // if not specified we allow anything
#else
case Type::Undefined: info->type = ZEND_TYPE_ENCODE(IS_UNDEF, arg.allowNull()); break; // undefined means we'll accept any type
case Type::Null: info->type = ZEND_TYPE_ENCODE(IS_UNDEF, arg.allowNull()); break; // this is likely an error, what good would accepting NULL be? accept anything
Expand All @@ -221,7 +242,7 @@ class Callable
default: info->type = ZEND_TYPE_ENCODE(IS_UNDEF, arg.allowNull()); break; // if not specified we allow anything
#endif
}

#if PHP_VERSION_ID < 80000
// from PHP 5.6 and onwards, an is_variadic property can be set, this
// specifies whether this argument is the first argument that specifies
// the type for a variable length list of arguments. For now we only
Expand All @@ -230,6 +251,7 @@ class Callable

// whether or not to pass the argument by reference
info->pass_by_reference = arg.byReference();
#endif
}

/**
Expand Down
Loading