Skip to content

Commit

Permalink
Merge pull request #364 from sjinks/issue-359
Browse files Browse the repository at this point in the history
Add support for PHP 7.2
  • Loading branch information
EmielBruijntjes authored Feb 9, 2018
2 parents 1b67997 + 0e5924a commit 801c01d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 2 deletions.
25 changes: 25 additions & 0 deletions zend/callable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,19 @@ void Callable::invoke(INTERNAL_FUNCTION_PARAMETERS)
uint32_t argc = EX(func)->common.num_args;
zend_arg_info* info = EX(func)->common.arg_info;

#if PHP_VERSION_ID < 70200
// Sanity check
assert(info[argc].class_name != nullptr && info[argc].name == nullptr);

// the callable we are retrieving
Callable *callable = reinterpret_cast<Callable*>(info[argc].class_name);
#else
// Sanity check
assert(info[argc].type != 0 && info[argc].name == nullptr);

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

// check if sufficient parameters were passed (for some reason this check
// is not done by Zend, so we do it here ourselves)
Expand Down Expand Up @@ -87,7 +95,11 @@ void Callable::initialize(zend_function_entry *entry, const char *classname, int
else
{
// install ourselves in the extra argument
#if PHP_VERSION_ID < 70200
_argv[_argc + 1].class_name = reinterpret_cast<const char*>(this);
#else
_argv[_argc + 1].type = reinterpret_cast<zend_type>(this);
#endif

// we use our own invoke method, which does a lookup
// in the map we just installed ourselves in
Expand All @@ -111,6 +123,7 @@ void Callable::initialize(zend_function_entry *entry, const char *classname, int
*/
void Callable::initialize(zend_internal_function_info *info, const char *classname) const
{
#if PHP_VERSION_ID < 70200
// store the classname
info->class_name = classname;

Expand All @@ -126,6 +139,18 @@ void Callable::initialize(zend_internal_function_info *info, const char *classna
// them to false
info->allow_null = false;
info->_is_variadic = false;
#else
info->required_num_args = _required;
info->return_reference = false;
info->_is_variadic = false;

if (_return == Type::Object) {
info->type = reinterpret_cast<zend_type>(classname);
}
else {
info->type = ZEND_TYPE_ENCODE(static_cast<unsigned char>(_return), 0);
}
#endif
}

/**
Expand Down
45 changes: 43 additions & 2 deletions zend/callable.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ class Callable
}

// initialize the extra argument
#if PHP_VERSION_ID < 70200
_argv[i].class_name = nullptr;
_argv[i].name = nullptr;
#else
_argv[i].type = 0;
#endif
}

/**
Expand Down Expand Up @@ -167,13 +171,18 @@ class Callable
// fill members
info->name = arg.name();

#if PHP_VERSION_ID < 70200
// are we filling an object
if (arg.type() == Type::Object) info->class_name = arg.classname();
else info->class_name = nullptr;

info->allow_null = arg.allowNull();
#endif

// set the correct type-hint
switch (arg.type())
{
#if PHP_VERSION_ID < 70200
case Type::Undefined: info->type_hint = IS_UNDEF; break; // undefined means we'll accept any type
case Type::Null: info->type_hint = IS_UNDEF; break; // this is likely an error, what good would accepting NULL be? accept anything
case Type::False: info->type_hint = _IS_BOOL; break; // accept true as well ;)
Expand All @@ -186,7 +195,41 @@ 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
#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
case Type::False: info->type = ZEND_TYPE_ENCODE(_IS_BOOL, arg.allowNull()); break; // accept true as well ;)
case Type::True: info->type = ZEND_TYPE_ENCODE(_IS_BOOL, arg.allowNull()); break; // accept false as well
case Type::Bool: info->type = ZEND_TYPE_ENCODE(_IS_BOOL, arg.allowNull()); break; // any bool will do, true, false, the options are limitless
case Type::Numeric: info->type = ZEND_TYPE_ENCODE(IS_LONG, arg.allowNull()); break; // accept integers here
case Type::Float: info->type = ZEND_TYPE_ENCODE(IS_DOUBLE, arg.allowNull()); break; // floating-point values welcome too
case Type::String: info->type = ZEND_TYPE_ENCODE(IS_STRING, arg.allowNull()); break; // accept strings, should auto-cast objects with __toString as well
case Type::Array: info->type = ZEND_TYPE_ENCODE(IS_ARRAY, arg.allowNull()); break; // array of anything (individual members cannot be restricted)
case Type::Object: // must be an object of the given classname
if (arg.classname()) {
if (!arg.allowNull()) {
info->type = reinterpret_cast<zend_type>(arg.classname());
}
else {
/// FIXME this leaks, although this happens only once during startup / MINIT
/// Probably not critical

const char* orig = arg.classname();
std::size_t len = std::strlen(orig);
char* newname = new char[len + 2]; // trailing NUL and heading ?
newname[0] = '?';
std::memcpy(newname + 1, orig, len + 1 /* Trailing NUL */);
}
}
else {
info->type = ZEND_TYPE_ENCODE(IS_OBJECT, arg.allowNull());
}

break;

case Type::Callable: info->type = ZEND_TYPE_ENCODE(IS_CALLABLE, arg.allowNull()); break; // anything that can be invoked
default: info->type = ZEND_TYPE_ENCODE(IS_UNDEF, arg.allowNull()); break; // if not specified we allow anything
#endif
}

// from PHP 5.6 and onwards, an is_variadic property can be set, this
Expand All @@ -195,8 +238,6 @@ class Callable
// support methods and functions with a fixed number of arguments.
info->is_variadic = false;

// this parameter is a regular type
info->allow_null = arg.allowNull();
info->pass_by_reference = arg.byReference();
}

Expand Down

0 comments on commit 801c01d

Please sign in to comment.