From 41c38731ee9be39e5eefd22dd72ed502e16ece1e Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 1 Aug 2022 17:13:12 +0100 Subject: [PATCH 1/3] Add regression test for broken non commutative multiplication --- ext/zend_test/test.c | 73 +++++++++++++++++++ ext/zend_test/test.stub.php | 6 ++ ext/zend_test/test_arginfo.h | 30 +++++++- .../tests/zend_non_commutative_test.phpt | 61 ++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 ext/zend_test/tests/zend_non_commutative_test.phpt diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index ca60fd82fcd51..5477d28d9aa3a 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -611,6 +611,73 @@ static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic) zend_forbid_dynamic_call(); } +// TODO HERE +/* ncm refers to non commutative multiplication */ +static zend_class_entry *ncm_ce; +static zend_object_handlers ncm_object_handlers; + +static zend_object* ncm_object_create_ex(zend_class_entry* ce, zend_long l) { + zend_object *obj = zend_objects_new(ce); + object_properties_init(obj, ce); + obj->handlers = &ncm_object_handlers; + ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l); + return obj; +} +static zend_object *ncm_object_create(zend_class_entry *ce) /* {{{ */ +{ + return ncm_object_create_ex(ce, 0); +} +/* }}} */ + +static inline void ncm_create(zval *target, zend_long l) /* {{{ */ +{ + ZVAL_OBJ(target, ncm_object_create_ex(ncm_ce, l)); +} + +#define IS_NCM(zval) \ + (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), ncm_ce)) + +static void ncm_subtraction(zval *result, zval *op1, zval *op2) +{ + zend_long val_1; + zend_long val_2; + if (IS_NCM(op1)) { + val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0)); + } else { + val_1 = zval_get_long(op1); + } + if (IS_NCM(op2)) { + val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0)); + } else { + val_2 = zval_get_long(op2); + } + + ncm_create(result, val_1 - val_2); +} + +static zend_result ncm_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) +{ + switch (opcode) { + case ZEND_MUL: + ncm_subtraction(result, op1, op2); + if (UNEXPECTED(EG(exception))) { return FAILURE; } + return SUCCESS; + default: + return FAILURE; + } +} + +PHP_METHOD(NonCommutativeMultiplication, __construct) +{ + zend_long l; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(l) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l); +} + PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals) @@ -713,6 +780,12 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_string_enum = register_class_ZendTestStringEnum(); zend_test_int_enum = register_class_ZendTestIntEnum(); + /* Non commutative multiplication class */ + ncm_ce = register_class_NonCommutativeMultiplication(); + ncm_ce->create_object = ncm_object_create; + memcpy(&ncm_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + ncm_object_handlers.do_operation = ncm_do_operation; + zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type); // Loading via dl() not supported with the observer API diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 45bbaedfc32ca..b69a076ee3437 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -98,6 +98,12 @@ enum ZendTestIntEnum: int { case Baz = -1; } + final class NonCommutativeMultiplication { + private int $val; + + public function __construct(int $val) {} + } + function zend_test_array_return(): array {} function zend_test_nullable_array_return(): ?array {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 6ea5277061d90..1ef512646516a 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: daa7be53e9009c66c814fb5b0407a6dfbe09679a */ + * Stub hash: 7662c2669de871d0be3a472c24da4ade0ee1dbe6 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -124,6 +124,10 @@ ZEND_END_ARG_INFO() #define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_void_return +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NonCommutativeMultiplication___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, val, IS_LONG, 0) +ZEND_END_ARG_INFO() + #if (PHP_VERSION_ID >= 80100) ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ZendTestNS_Foo_method, 0, 0, IS_LONG, 0) #else @@ -175,6 +179,7 @@ static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override); static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override); static ZEND_METHOD(ZendTestForbidDynamicCall, call); static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic); +static ZEND_METHOD(NonCommutativeMultiplication, __construct); static ZEND_METHOD(ZendTestNS_Foo, method); static ZEND_METHOD(ZendTestNS_UnlikelyCompileError, method); static ZEND_METHOD(ZendTestNS2_Foo, method); @@ -282,6 +287,12 @@ static const zend_function_entry class_ZendTestIntEnum_methods[] = { }; +static const zend_function_entry class_NonCommutativeMultiplication_methods[] = { + ZEND_ME(NonCommutativeMultiplication, __construct, arginfo_class_NonCommutativeMultiplication___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + + static const zend_function_entry class_ZendTestNS_Foo_methods[] = { ZEND_ME(ZendTestNS_Foo, method, arginfo_class_ZendTestNS_Foo_method, ZEND_ACC_PUBLIC) ZEND_FE_END @@ -566,6 +577,23 @@ static zend_class_entry *register_class_ZendTestIntEnum(void) } #endif +static zend_class_entry *register_class_NonCommutativeMultiplication(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "NonCommutativeMultiplication", class_NonCommutativeMultiplication_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL; + + zval property_val_default_value; + ZVAL_UNDEF(&property_val_default_value); + zend_string *property_val_name = zend_string_init("val", sizeof("val") - 1, 1); + zend_declare_typed_property(class_entry, property_val_name, &property_val_default_value, ZEND_ACC_PRIVATE, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_val_name); + + return class_entry; +} + static zend_class_entry *register_class_ZendTestNS_Foo(void) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/zend_non_commutative_test.phpt b/ext/zend_test/tests/zend_non_commutative_test.phpt new file mode 100644 index 0000000000000..827d83d33a645 --- /dev/null +++ b/ext/zend_test/tests/zend_non_commutative_test.phpt @@ -0,0 +1,61 @@ +--TEST-- +Zend: test non commutative multiplication object handler +--EXTENSIONS-- +zend_test +--XFAIL-- +Broken non commutative multiplication with more than 2 ops +--FILE-- + +--EXPECT-- +object(NonCommutativeMultiplication)#1 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(10) +} +object(NonCommutativeMultiplication)#2 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(50) +} +object(NonCommutativeMultiplication)#3 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(100) +} +object(NonCommutativeMultiplication)#5 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(30) +} +int(40) +object(NonCommutativeMultiplication)#4 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(40) +} +int(-140) +object(NonCommutativeMultiplication)#5 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(-140) +} +int(-60) +object(NonCommutativeMultiplication)#4 (1) { + ["val":"NonCommutativeMultiplication":private]=> + int(-60) +} From 7a954ac89ed5269f173b87cbd9ec02555877dd57 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Tue, 2 Aug 2022 17:02:00 +0100 Subject: [PATCH 2/3] Do not mark multiplication op as commutative As it might not be when an internal object overloads the multiplication operation --- Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 71 ++++++++++++++++--- Zend/zend_vm_handlers.h | 3 + Zend/zend_vm_opcodes.c | 2 +- .../tests/zend_non_commutative_test.phpt | 2 - 5 files changed, 67 insertions(+), 15 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index df042aa8f3199..cbec671c77077 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -162,7 +162,7 @@ ZEND_VM_HELPER(zend_mul_helper, ANY, ANY, zval *op_1, zval *op_2) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_COLD_CONSTCONST_HANDLER(3, ZEND_MUL, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(COMMUTATIVE)) +ZEND_VM_COLD_CONSTCONST_HANDLER(3, ZEND_MUL, CONST|TMPVARCV, CONST|TMPVARCV) { USE_OPLINE zval *op1, *op2, *result; @@ -7591,7 +7591,7 @@ ZEND_VM_HOT_NOCONST_HANDLER(198, ZEND_JMP_NULL, CONST|TMP|VAR|CV, JMP_ADDR) uint32_t short_circuiting_type = opline->extended_value & ZEND_SHORT_CIRCUITING_CHAIN_MASK; if (EXPECTED(short_circuiting_type == ZEND_SHORT_CIRCUITING_CHAIN_EXPR)) { ZVAL_NULL(result); - if (OP1_TYPE == IS_CV + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF) && (opline->extended_value & ZEND_JMP_NULL_BP_VAR_IS) == 0 ) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b3a48b80f480b..3c7e7839c0d2b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7875,6 +7875,47 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SUB_SPEC_CONST_TMP ZEND_VM_TAIL_CALL(zend_sub_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MUL_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *op1, *op2, *result; + double d1, d2; + + op1 = RT_CONSTANT(opline, opline->op1); + op2 = EX_VAR(opline->op2.var); + if (1 && IS_CONST == IS_CONST && (IS_TMP_VAR|IS_VAR|IS_CV) == IS_CONST) { + /* pass */ + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + zend_long overflow; + + result = EX_VAR(opline->result.var); + ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow); + Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG; + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = (double)Z_LVAL_P(op1); + d2 = Z_DVAL_P(op2); + goto mul_double; + } + } else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) { + if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) { + d1 = Z_DVAL_P(op1); + d2 = Z_DVAL_P(op2); +mul_double: + result = EX_VAR(opline->result.var); + ZVAL_DOUBLE(result, d1 * d2); + ZEND_VM_NEXT_OPCODE(); + } else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) { + d1 = Z_DVAL_P(op1); + d2 = (double)Z_LVAL_P(op2); + goto mul_double; + } + } + + ZEND_VM_TAIL_CALL(zend_mul_helper_SPEC(op1, op2 ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_MOD_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -52331,10 +52372,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SUB_SPEC_TMPVARCV_TMPVARCV_LABEL, (void*)&&ZEND_MUL_SPEC_CONST_CONST_LABEL, + (void*)&&ZEND_MUL_SPEC_CONST_TMPVARCV_LABEL, + (void*)&&ZEND_MUL_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_NULL_LABEL, - (void*)&&ZEND_NULL_LABEL, + (void*)&&ZEND_MUL_SPEC_CONST_TMPVARCV_LABEL, (void*)&&ZEND_MUL_SPEC_TMPVARCV_CONST_LABEL, (void*)&&ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_LABEL, (void*)&&ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_LABEL, @@ -56637,6 +56678,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_SUB_SPEC_CONST_TMPVARCV) ZEND_SUB_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_MUL_SPEC_CONST_TMPVARCV): + VM_TRACE(ZEND_MUL_SPEC_CONST_TMPVARCV) + ZEND_MUL_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_MOD_SPEC_CONST_TMPVARCV): VM_TRACE(ZEND_MOD_SPEC_CONST_TMPVARCV) ZEND_MOD_SPEC_CONST_TMPVARCV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -60388,10 +60433,10 @@ void zend_vm_init(void) ZEND_NULL_HANDLER, ZEND_SUB_SPEC_TMPVARCV_TMPVARCV_HANDLER, ZEND_MUL_SPEC_CONST_CONST_HANDLER, + ZEND_MUL_SPEC_CONST_TMPVARCV_HANDLER, + ZEND_MUL_SPEC_CONST_TMPVARCV_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_MUL_SPEC_CONST_TMPVARCV_HANDLER, ZEND_MUL_SPEC_TMPVARCV_CONST_HANDLER, ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_HANDLER, ZEND_MUL_SPEC_TMPVARCV_TMPVARCV_HANDLER, @@ -63792,7 +63837,7 @@ void zend_vm_init(void) 0, 1 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 26 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 51 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE, + 51 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 76 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 101 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 126 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -64258,24 +64303,30 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t } break; case ZEND_MUL: - if (op->op1_type < op->op2_type) { - zend_swap_operands(op); - } if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } spec = 2699 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + if (op->op1_type < op->op2_type) { + zend_swap_operands(op); + } } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } spec = 2724 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + if (op->op1_type < op->op2_type) { + zend_swap_operands(op); + } } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } spec = 2749 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; + if (op->op1_type < op->op2_type) { + zend_swap_operands(op); + } } break; case ZEND_IS_IDENTICAL: diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index d07c63d89f4f7..45898cf1de60b 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -33,6 +33,9 @@ _(48, ZEND_SUB_SPEC_TMPVARCV_TMPVARCV) \ _(50, ZEND_SUB_SPEC_TMPVARCV_TMPVARCV) \ _(51, ZEND_MUL_SPEC_CONST_CONST) \ + _(52, ZEND_MUL_SPEC_CONST_TMPVARCV) \ + _(53, ZEND_MUL_SPEC_CONST_TMPVARCV) \ + _(55, ZEND_MUL_SPEC_CONST_TMPVARCV) \ _(56, ZEND_MUL_SPEC_TMPVARCV_CONST) \ _(57, ZEND_MUL_SPEC_TMPVARCV_TMPVARCV) \ _(58, ZEND_MUL_SPEC_TMPVARCV_TMPVARCV) \ diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index c3f5e9d427aa4..5f90c0e24e438 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -232,7 +232,7 @@ static uint32_t zend_vm_opcodes_flags[203] = { 0x00000000, 0x00000b0b, 0x00000b0b, - 0x80000b0b, + 0x00000b0b, 0x00000707, 0x00000b0b, 0x00000b0b, diff --git a/ext/zend_test/tests/zend_non_commutative_test.phpt b/ext/zend_test/tests/zend_non_commutative_test.phpt index 827d83d33a645..637a88f016dd8 100644 --- a/ext/zend_test/tests/zend_non_commutative_test.phpt +++ b/ext/zend_test/tests/zend_non_commutative_test.phpt @@ -2,8 +2,6 @@ Zend: test non commutative multiplication object handler --EXTENSIONS-- zend_test ---XFAIL-- -Broken non commutative multiplication with more than 2 ops --FILE-- Date: Thu, 4 Aug 2022 13:42:56 +0100 Subject: [PATCH 3/3] Fix test which now display types of operand in a different order --- Zend/tests/operator_unsupported_types.phpt | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Zend/tests/operator_unsupported_types.phpt b/Zend/tests/operator_unsupported_types.phpt index c90f0e374ab56..a0048b107b284 100644 --- a/Zend/tests/operator_unsupported_types.phpt +++ b/Zend/tests/operator_unsupported_types.phpt @@ -279,20 +279,20 @@ Unsupported operand types: string - string Warning: A non-numeric value encountered Unsupported operand types: string - string Unsupported operand types: array * array -Unsupported operand types: stdClass * array -Unsupported operand types: resource * array +Unsupported operand types: array * stdClass +Unsupported operand types: array * resource Unsupported operand types: array * string Unsupported operand types: stdClass * array Unsupported operand types: stdClass * stdClass Unsupported operand types: stdClass * resource Unsupported operand types: stdClass * string Unsupported operand types: resource * array -Unsupported operand types: stdClass * resource +Unsupported operand types: resource * stdClass Unsupported operand types: resource * resource Unsupported operand types: resource * string Unsupported operand types: string * array -Unsupported operand types: stdClass * string -Unsupported operand types: resource * string +Unsupported operand types: string * stdClass +Unsupported operand types: string * resource Unsupported operand types: string * string Unsupported operand types: array * null Unsupported operand types: null * array @@ -310,33 +310,35 @@ Unsupported operand types: array * string Warning: A non-numeric value encountered Unsupported operand types: string * array Unsupported operand types: stdClass * null -Unsupported operand types: stdClass * null -Unsupported operand types: stdClass * bool -Unsupported operand types: stdClass * bool +Unsupported operand types: null * stdClass Unsupported operand types: stdClass * bool +Unsupported operand types: bool * stdClass Unsupported operand types: stdClass * bool +Unsupported operand types: bool * stdClass Unsupported operand types: stdClass * int -Unsupported operand types: stdClass * int -Unsupported operand types: stdClass * float +Unsupported operand types: int * stdClass Unsupported operand types: stdClass * float +Unsupported operand types: float * stdClass Unsupported operand types: stdClass * string +Unsupported operand types: string * stdClass Unsupported operand types: stdClass * string -Unsupported operand types: stdClass * string -Unsupported operand types: stdClass * string -Unsupported operand types: resource * null +Warning: A non-numeric value encountered +Unsupported operand types: string * stdClass Unsupported operand types: resource * null +Unsupported operand types: null * resource Unsupported operand types: resource * bool +Unsupported operand types: bool * resource Unsupported operand types: resource * bool -Unsupported operand types: resource * bool -Unsupported operand types: resource * bool -Unsupported operand types: resource * int +Unsupported operand types: bool * resource Unsupported operand types: resource * int +Unsupported operand types: int * resource Unsupported operand types: resource * float -Unsupported operand types: resource * float -Unsupported operand types: resource * string -Unsupported operand types: resource * string +Unsupported operand types: float * resource Unsupported operand types: resource * string +Unsupported operand types: string * resource Unsupported operand types: resource * string +Warning: A non-numeric value encountered +Unsupported operand types: string * resource Unsupported operand types: string * null Unsupported operand types: null * string Unsupported operand types: string * bool