function). (Li-Wen Hsu)
. Fixed bug #54043 (Remove inconsitency of internal exceptions and user
defined exceptions). (Nikita)
+ . Fixed bug #53033 (Mathematical operations convert objects to integers).
+ (Nikita)
+ . Fixed bug #73108 (Internal class cast handler uses integer instead of
+ float). (Nikita)
- BCMath:
. Fixed bug #66364 (BCMath bcmul ignores scale parameter). (cmb)
. Fixed bug #74941 (session fails to start after having headers sent).
(morozov)
+- SimpleXML:
+ . Fixed bug #54973 (SimpleXML casts integers wrong). (Nikita)
+
- SOAP:
. Fixed bug #75464 (Wrong reflection on SoapClient::__setSoapHeaders). (villfa)
BCMath:
. All warnings thrown by BCMath functions are now using PHP's error handling.
- Formerly some warnings have directly been written to stderr.
+ Formerly some warnings have directly been written to stderr.
. bcmul() and bcpow() now return numbers with the requested scale. Formerly,
the returned numbers may have omitted trailing decimal zeroes.
executed. Previously all autoloaders were executed and exceptions were
chained.
+SimpleXML:
+ . Mathematic operations involving SimpleXML objects will now treat the text as
+ an integer or float, whichever is more appropriate. Previously values were
+ treated as integers unconditionally.
+
Standard:
. getimagesize() and related functions now report the mime type of BMP images
as image/bmp instead of image/x-ms-bmp, since the former has been registered
. Support for Birdstep has been removed.
ZIP:
- . Bunled libzip has been dropped,
+ . Bundled libzip has been dropped,
system library is now required.
========================================
g. zend_get_parameters()
h. zend_register_persistent_resource()
i. RAND_RANGE()
+ j. cast_object() with _IS_NUMBER
2. Build system changes
a. Unix build system changes
i. The RANGE_RANGE() macro has been removed. php_mt_rand_range() should be
used instead.
+ j. The cast_object() object handler now also accepts the _IS_NUMBER type. The
+ handler should return either an integer or float value in this case,
+ whichever is more appropriate.
+
========================
2. Build system changes
========================
echo "Done\n";
?>
--EXPECTF--
-Notice: Object of class stdClass could not be converted to int in %sadd_002.php on line %d
+Notice: Object of class stdClass could not be converted to number in %sadd_002.php on line %d
Exception: Unsupported operand types
-Notice: Object of class stdClass could not be converted to int in %s 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
Stack trace:
echo "Done\n";
?>
--EXPECTF--
-Notice: Object of class stdClass could not be converted to int 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: Object of class stdClass could not be converted to int in %s 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
Stack trace:
--EXPECTF--
Deprecated: assert(): Calling assert() with a string argument is deprecated in %s on line %d
-Notice: Object of class stdClass could not be converted to int in %s on line %d
+Notice: Object of class stdClass could not be converted to number in %s on line %d
int(2)
try { new d + new d; } catch (Exception $e) { print "Exception properly caught\n"; }
?>
--EXPECTF--
-Notice: Object of class d could not be converted to int in %sbug73337.php on line 3
+Notice: Object of class d could not be converted to number in %sbug73337.php on line 3
-Notice: Object of class d could not be converted to int in %sbug73337.php on line 3
+Notice: Object of class d could not be converted to number in %sbug73337.php on line 3
Exception properly caught
return "array";
case IS_VOID:
return "void";
+ case _IS_NUMBER:
+ return "number";
default:
return "unknown";
}
zend_error(E_NOTICE, "Object of class %s could not be converted to float", ZSTR_VAL(ce->name));
ZVAL_DOUBLE(writeobj, 1);
return SUCCESS;
+ case _IS_NUMBER:
+ ce = Z_OBJCE_P(readobj);
+ zend_error(E_NOTICE, "Object of class %s could not be converted to number", ZSTR_VAL(ce->name));
+ ZVAL_LONG(writeobj, 1);
+ return SUCCESS;
default:
ZVAL_NULL(writeobj);
break;
}
/* }}} */
+/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
+#define convert_object_to_type(op, dst, ctype, conv_func) \
+ ZVAL_UNDEF(dst); \
+ if (Z_OBJ_HT_P(op)->cast_object) { \
+ if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) { \
+ zend_error(E_RECOVERABLE_ERROR, \
+ "Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
+ zend_get_type_by_const(ctype)); \
+ } \
+ } else if (Z_OBJ_HT_P(op)->get) { \
+ zval *newop = Z_OBJ_HT_P(op)->get(op, dst); \
+ if (Z_TYPE_P(newop) != IS_OBJECT) { \
+ /* for safety - avoid loop */ \
+ ZVAL_COPY_VALUE(dst, newop); \
+ conv_func(dst); \
+ } \
+ }
+
+/* }}} */
+
void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent) /* {{{ */
{
try_again:
}
break;
case IS_OBJECT:
- convert_to_long_base(op, 10);
+ {
+ zval dst;
+
+ convert_object_to_type(op, &dst, _IS_NUMBER, convert_scalar_to_number);
+ zval_dtor(op);
+
+ if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) {
+ ZVAL_COPY_VALUE(op, &dst);
+ } else {
+ ZVAL_LONG(op, 1);
+ }
+ }
break;
}
}
break; \
case IS_OBJECT: \
ZVAL_COPY(&(holder), op); \
- convert_to_long_base(&(holder), 10); \
+ _convert_scalar_to_number(&(holder), silent); \
if (UNEXPECTED(EG(exception))) { \
if (result != op1) { \
ZVAL_UNDEF(result); \
} \
return FAILURE; \
} \
- if (Z_TYPE(holder) == IS_LONG) { \
+ if (Z_TYPE(holder) == IS_LONG || Z_TYPE(holder) == IS_DOUBLE) { \
if (op == result) { \
zval_ptr_dtor(op); \
- ZVAL_LONG(op, Z_LVAL(holder)); \
+ ZVAL_COPY(op, &(holder)); \
} else { \
(op) = &(holder); \
} \
/* }}} */
-/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
-#define convert_object_to_type(op, dst, ctype, conv_func) \
- ZVAL_UNDEF(dst); \
- if (Z_OBJ_HT_P(op)->cast_object) { \
- if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) { \
- zend_error(E_RECOVERABLE_ERROR, \
- "Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
- zend_get_type_by_const(ctype)); \
- } \
- } else if (Z_OBJ_HT_P(op)->get) { \
- zval *newop = Z_OBJ_HT_P(op)->get(op, dst); \
- if (Z_TYPE_P(newop) != IS_OBJECT) { \
- /* for safety - avoid loop */ \
- ZVAL_COPY_VALUE(dst, newop); \
- conv_func(dst); \
- } \
- }
-
-/* }}} */
-
#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op, op_func) \
do { \
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { \
#define IS_CALLABLE 17
#define IS_ITERABLE 18
#define IS_VOID 19
+#define _IS_NUMBER 20
static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
return pz->u1.v.type;
switch(type) {
case IS_LONG:
+ case _IS_NUMBER:
vt = VT_INT;
break;
case IS_DOUBLE:
gmpnum = GET_GMP_FROM_ZVAL(readobj);
ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
return SUCCESS;
+ case _IS_NUMBER:
+ gmpnum = GET_GMP_FROM_ZVAL(readobj);
+ if (mpz_fits_slong_p(gmpnum)) {
+ ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
+ } else {
+ ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
+ }
+ return SUCCESS;
default:
return FAILURE;
}
string(1) "1"
string(1) "0"
-Notice: Object of class NumberFormatter could not be converted to int in %s on line %d
+Notice: Object of class NumberFormatter could not be converted to number in %s on line %d
string(1) "1"
case IS_DOUBLE:
convert_to_double(object);
break;
+ case _IS_NUMBER:
+ convert_scalar_to_number(object);
+ break;
default:
return FAILURE;
}
--- /dev/null
+--TEST--
+Bug #53033: Mathematical operations convert objects to integers
+--FILE--
+<?php
+
+$x = simplexml_load_string('<x>2.5</x>');
+var_dump($x*1);
+// type of other operand is irrelevant
+var_dump($x*1.0);
+
+// strings behave differently
+$y = '2.5';
+var_dump($y*1);
+var_dump((string)$x*1);
+
+?>
+--EXPECT--
+float(2.5)
+float(2.5)
+float(2.5)
+float(2.5)
--- /dev/null
+--TEST--
+Bug #54973: SimpleXML casts integers wrong
+--FILE--
+<?php
+$xml = simplexml_load_string("<xml><number>9223372036854775808</number></xml>");
+
+var_dump($xml->number);
+
+$int = $xml->number / 1024 / 1024 / 1024;
+var_dump($int);
+
+$double = (double) $xml->number / 1024 / 1024 / 1024;
+var_dump($double);
+?>
+--EXPECT--
+object(SimpleXMLElement)#2 (1) {
+ [0]=>
+ string(19) "9223372036854775808"
+}
+float(8589934592)
+float(8589934592)
-- Iteration 13 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
int(1)
-- Iteration 14 --
-- Iteration 16 --
int(%d)
-===Done===
\ No newline at end of file
+===Done===
-- Iteration 13 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
float(1)
-- Iteration 14 --
-- Iteration 13 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
float(1)
-- Iteration 14 --
-- Iteration 23 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
int(1)
-- Iteration 24 --
-- Iteration 23 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
int(1)
-- Iteration 24 --
-- Iteration 23 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
float(20.3)
-- Iteration 24 --
-- Iteration 23 --
-Notice: Object of class classA could not be converted to int in %s on line %d
+Notice: Object of class classA could not be converted to number in %s on line %d
float(1)
-- Iteration 24 --
switch (type) {
case IS_LONG:
+ case _IS_NUMBER:
ZVAL_LONG(out, 0);
break;
switch(type) {
case IS_LONG:
+ case _IS_NUMBER:
ZVAL_LONG(out, 0);
break;