Skip to content
Closed
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: 4 additions & 0 deletions Zend/tests/add_002.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ var_dump($c);
echo "Done\n";
?>
--EXPECTF--
Notice: You have to implement the __add function in class stdClass to use this operator with an object in %sadd_002.php on line %d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notice doesn't make sense for non-user defined classes!
I see no point in emitting it here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this message does not make sense here, but I'm fine with having a notice on object to int conversion (which is undefined behavior) here.


Notice: Object of class stdClass could not be converted to number in %sadd_002.php on line %d

Exception: Unsupported operand types

Notice: You have to implement the __add function in class stdClass to use this operator with an object in %sadd_002.php on line %d

Notice: Object of class stdClass could not be converted to number in %s on line %d

Fatal error: Uncaught Error: Unsupported operand types in %s:%d
Expand Down
4 changes: 4 additions & 0 deletions Zend/tests/add_003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ var_dump($c);
echo "Done\n";
?>
--EXPECTF--
Notice: You have to implement the __add function in class stdClass to use this operator with an object in %sadd_003.php on line %d

Notice: Object of class stdClass could not be converted to number in %sadd_003.php on line %d

Exception: Unsupported operand types

Notice: You have to implement the __add function in class stdClass to use this operator with an object in %sadd_003.php on line %d

Notice: Object of class stdClass could not be converted to number in %s on line %d

Fatal error: Uncaught Error: Unsupported operand types in %s:%d
Expand Down
16 changes: 16 additions & 0 deletions Zend/zend.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ struct _zend_class_entry {
zend_function *__callstatic;
zend_function *__tostring;
zend_function *__debugInfo;

/* magic functions for operator overloading */
zend_function *__add;
zend_function *__sub;
zend_function *__mul;
zend_function *__pow;
zend_function *__div;
zend_function *__concat;
zend_function *__mod;
zend_function *__shiftLeft;
zend_function *__shiftRight;
zend_function *__bitwiseOr;
zend_function *__bitwiseAnd;
zend_function *__bitwiseXor;
zend_function *__bitwiseNot;

zend_function *serialize_func;
zend_function *unserialize_func;

Expand Down
145 changes: 145 additions & 0 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,110 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce,
} else if (name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1 &&
!memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && fptr->common.num_args != 0) {
zend_error(error_type, "Method %s::%s() cannot take arguments", ZSTR_VAL(ce->name), ZEND_DEBUGINFO_FUNC_NAME);
} else if (name_len == sizeof(ZEND_ADD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ADD_FUNC_NAME, sizeof(ZEND_ADD_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_ADD_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_ADD_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_ADD_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_SUB_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SUB_FUNC_NAME, sizeof(ZEND_SUB_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_SUB_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_SUB_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_SUB_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_MUL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_MUL_FUNC_NAME, sizeof(ZEND_MUL_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_MUL_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_MUL_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_MUL_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_DIV_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DIV_FUNC_NAME, sizeof(ZEND_DIV_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_DIV_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_DIV_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_DIV_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_POW_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_POW_FUNC_NAME, sizeof(ZEND_POW_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_POW_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_POW_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_POW_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_MOD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_MOD_FUNC_NAME, sizeof(ZEND_MOD_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_MOD_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_MOD_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_MOD_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_CONCAT_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CONCAT_FUNC_NAME, sizeof(ZEND_CONCAT_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), ZEND_CONCAT_FUNC_NAME);
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_CONCAT_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), ZEND_CONCAT_FUNC_NAME);
}
} else if (name_len == sizeof(ZEND_SHIFT_LEFT_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SHIFT_LEFT_FUNC_NAME, sizeof(ZEND_SHIFT_LEFT_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), "__shiftLeft");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), "__shiftLeft");
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__shiftLeft");
}
} else if (name_len == sizeof(ZEND_SHIFT_RIGHT_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SHIFT_RIGHT_FUNC_NAME, sizeof(ZEND_SHIFT_RIGHT_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), "__shiftRight");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), "__shiftRight");
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__shiftRight");
}
} else if (name_len == sizeof(ZEND_OR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_OR_FUNC_NAME, sizeof(ZEND_OR_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), "__bitwiseOr");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), "__bitwiseOr");
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__bitwiseOr");
}
} else if (name_len == sizeof(ZEND_AND_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AND_FUNC_NAME, sizeof(ZEND_AND_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), "__bitwiseAnd");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints", ZSTR_VAL(ce->name), ZEND_ADD_FUNC_NAME);
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__bitwisAnd");
}
} else if (name_len == sizeof(ZEND_XOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_XOR_FUNC_NAME, sizeof(ZEND_XOR_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 2) {
zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ZSTR_VAL(ce->name), "__bitwiseXor");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints.", ZSTR_VAL(ce->name), "__bitwiseXor");
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__bitwiseXor");
}
} else if (name_len == sizeof(ZEND_NOT_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_NOT_FUNC_NAME, sizeof(ZEND_NOT_FUNC_NAME) - 1)) {
if (fptr->common.num_args != 1) {
zend_error(error_type, "Method %s::%s() must take exactly 1 arguments", ZSTR_VAL(ce->name), "__bitwiseNot");
} else if (fptr->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_error(error_type, "Method %s::%s() can not declare argument typehints.", ZSTR_VAL(ce->name), "__bitwiseNot");
} else if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ZSTR_VAL(ce->name), "__bitwiseNot");
}
}
}
/* }}} */
Expand All @@ -1981,6 +2085,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
HashTable *target_function_table = function_table;
int error_type;
zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL, *serialize_func = NULL, *unserialize_func = NULL;
zend_function *__add = NULL, *__sub = NULL, *__mul = NULL, *__div = NULL, *__pow = NULL, *__concat = NULL, *__mod = NULL, *__bitwiseAnd = NULL, *__bitwiseOr = NULL, *__bitwiseXor = NULL, *__bitwiseNot = NULL, *__shiftLeft = NULL, *__shiftRight = NULL;
zend_string *lowercase_name;
size_t fname_len;
const char *lc_class_name = NULL;
Expand Down Expand Up @@ -2176,6 +2281,32 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
scope->ce_flags |= ZEND_ACC_USE_GUARDS;
} else if (zend_string_equals_literal(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME)) {
__debugInfo = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_ADD_FUNC_NAME)) {
__add = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_SUB_FUNC_NAME)) {
__sub = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_MUL_FUNC_NAME)) {
__mul = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_DIV_FUNC_NAME)) {
__div = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_POW_FUNC_NAME)) {
__pow = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_MOD_FUNC_NAME)) {
__mod = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_CONCAT_FUNC_NAME)) {
__concat = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_AND_FUNC_NAME)) {
__bitwiseAnd = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_OR_FUNC_NAME)) {
__bitwiseOr = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_XOR_FUNC_NAME)) {
__bitwiseXor = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_NOT_FUNC_NAME)) {
__bitwiseNot = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_SHIFT_LEFT_FUNC_NAME)) {
__shiftLeft = reg_function;
} else if (zend_string_equals_literal(lowercase_name, ZEND_SHIFT_RIGHT_FUNC_NAME)) {
__shiftRight = reg_function;
} else {
reg_function = NULL;
}
Expand Down Expand Up @@ -2218,6 +2349,19 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
scope->__debugInfo = __debugInfo;
scope->serialize_func = serialize_func;
scope->unserialize_func = unserialize_func;
scope->__add = __add;
scope->__sub = __sub;
scope->__mul = __mul;
scope->__div = __div;
scope->__pow = __pow;
scope->__mod = __mod;
scope->__bitwiseAnd = __bitwiseAnd;
scope->__bitwiseOr = __bitwiseOr;
scope->__bitwiseXor = __bitwiseXor;
scope->__bitwiseNot = __bitwiseNot;
scope->__concat = __concat;
scope->__shiftLeft = __shiftLeft;
scope->__shiftRight = __shiftRight;
if (ctor) {
ctor->common.fn_flags |= ZEND_ACC_CTOR;
if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
Expand Down Expand Up @@ -2288,6 +2432,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
if (clone && (clone->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
zend_error_noreturn(E_CORE_ERROR, "%s::%s() cannot declare a return type", ZSTR_VAL(scope->name), ZSTR_VAL(clone->common.function_name));
}

efree((char*)lc_class_name);
}
return SUCCESS;
Expand Down
85 changes: 70 additions & 15 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1832,6 +1832,19 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
ce->serialize_func = NULL;
ce->unserialize_func = NULL;
ce->__debugInfo = NULL;
ce->__add = NULL;
ce->__sub = NULL;
ce->__mul = NULL;
ce->__div = NULL;
ce->__pow = NULL;
ce->__mod = NULL;
ce->__concat = NULL;
ce->__shiftLeft = NULL;
ce->__shiftRight = NULL;
ce->__bitwiseAnd = NULL;
ce->__bitwiseOr = NULL;
ce->__bitwiseXor = NULL;
ce->__bitwiseNot = NULL;
if (ce->type == ZEND_INTERNAL_CLASS) {
ce->info.internal.module = NULL;
ce->info.internal.builtin_functions = NULL;
Expand Down Expand Up @@ -6092,6 +6105,45 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__debugInfo", 0);
ce->__debugInfo = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_ADD_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__add", 1);
ce->__add = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_SUB_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__sub", 1);
ce->__sub = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_MUL_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__mul", 1);
ce->__mul = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_POW_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__pow", 1);
ce->__pow = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_DIV_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__div", 1);
ce->__div = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_CONCAT_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__concat", 1);
ce->__concat = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_MOD_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__mod", 1);
ce->__mod = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_SHIFT_LEFT_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__shiftLeft", 1);
ce->__shiftLeft = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_SHIFT_RIGHT_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__shiftRight", 1);
ce->__shiftRight = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_OR_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__bitwiseOr", 1);
ce->__bitwiseOr = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_AND_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__bitwiseAnd", 1);
ce->__bitwiseAnd = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_XOR_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__bitwiseXor", 1);
ce->__bitwiseXor = (zend_function *) op_array;
} else if (zend_string_equals_literal(lcname, ZEND_NOT_FUNC_NAME)) {
zend_check_magic_method_attr(fn_flags, "__bitwiseNot", 1);
ce->__bitwiseNot = (zend_function *) op_array;
}

zend_string_release_ex(lcname, 0);
Expand Down Expand Up @@ -7395,23 +7447,26 @@ void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
}
}
} else if (opcode == ZEND_CONCAT) {
/* convert constant operands to strings at compile-time */
if (left_node.op_type == IS_CONST) {
if (Z_TYPE(left_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&left_node, ZEND_CAST, &left_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&left_node.u.constant);
/* Only do optimization if none of the operands are objects (they can have overloaded concat operator) */
if(!(left_node.op_type == IS_OBJECT || right_node.op_type == IS_OBJECT)) {
/* convert constant operands to strings at compile-time */
if (left_node.op_type == IS_CONST) {
if (Z_TYPE(left_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&left_node, ZEND_CAST, &left_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&left_node.u.constant);
}
}
}
if (right_node.op_type == IS_CONST) {
if (Z_TYPE(right_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&right_node, ZEND_CAST, &right_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&right_node.u.constant);
if (right_node.op_type == IS_CONST) {
if (Z_TYPE(right_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&right_node, ZEND_CAST, &right_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&right_node.u.constant);
}
}
if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
opcode = ZEND_FAST_CONCAT;
}
}
if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
opcode = ZEND_FAST_CONCAT;
}
}
zend_emit_op_tmp(result, opcode, &left_node, &right_node);
Expand Down
Loading