mirror of
https://github.com/php/php-src.git
synced 2024-11-23 09:54:15 +08:00
[RFC] Path to Saner Increment/Decrement operators (#10358)
* Add behavioural tests for incdec operators * Add support to ++/-- for objects castable to _IS_NUMBER * Add str_increment() function * Add str_decrement() function RFC: https://wiki.php.net/rfc/saner-inc-dec-operators Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com> Co-authored-by: Arnaud Le Blanc <arnaud.lb@gmail.com>
This commit is contained in:
parent
2f318cfb06
commit
d8696f9216
19
UPGRADING
19
UPGRADING
@ -118,6 +118,14 @@ PHP 8.3 UPGRADE NOTES
|
||||
4. Deprecated Functionality
|
||||
========================================
|
||||
|
||||
- Core
|
||||
. Using the ++ operator on empty, non-numeric, or non-alphanumeric strings
|
||||
is now deprecated. Moreover, incrementing non-numeric strings is soft
|
||||
deprecated and the new str_increment() function should be used instead.
|
||||
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
|
||||
. Using the -- operator on empty or non-numeric strings is now deprecated.
|
||||
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
|
||||
|
||||
- Intl
|
||||
. The U_MULTIPLE_DECIMAL_SEP*E*RATORS constant had been deprecated, using
|
||||
the U_MULTIPLE_DECIMAL_SEP*A*RATORS instead is recommended.
|
||||
@ -303,6 +311,10 @@ PHP 8.3 UPGRADE NOTES
|
||||
- Sockets:
|
||||
. Added socket_atmark to checks if the socket is OOB marked.
|
||||
|
||||
- Standard:
|
||||
. Added the str_increment() and str_decrement() functions.
|
||||
RFC: https://wiki.php.net/rfc/saner-inc-dec-operators
|
||||
|
||||
- Zip:
|
||||
. Added ZipArchive::setArchiveFlag and ZipArchive::getArchiveFlag methods.
|
||||
|
||||
@ -324,6 +336,13 @@ PHP 8.3 UPGRADE NOTES
|
||||
not reachable except by iterating over the WeakMap (reachability via
|
||||
iteration is considered weak). Previously, such entries would never be
|
||||
automatically removed. (See GH-10932.)
|
||||
. The ++ and -- operators now emit warnings when attempting to increment
|
||||
values of type bool as this will change in the next major version.
|
||||
A warning is emitted when trying to decrement values of type null, as
|
||||
this will change in the next major version.
|
||||
Internal objects that implement an _IS_NUMBER cast but not a do_operator
|
||||
handler that overrides addition and substraction now can be incremented
|
||||
and decrement as if one would do $o += 1 or $o -= 1
|
||||
|
||||
- DOM:
|
||||
. The DOM lifetime mechanism has been reworked such that implicitly removed
|
||||
|
@ -664,9 +664,14 @@ static inline zend_result ct_eval_assign_obj(zval *result, zval *value, const zv
|
||||
}
|
||||
|
||||
static inline zend_result ct_eval_incdec(zval *result, uint8_t opcode, zval *op1) {
|
||||
/* As of PHP 8.3 with the warning/deprecation notices any type other than int/double/null will emit a diagnostic
|
||||
if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) {
|
||||
return FAILURE;
|
||||
}
|
||||
*/
|
||||
if (Z_TYPE_P(op1) != IS_LONG && Z_TYPE_P(op1) != IS_DOUBLE && Z_TYPE_P(op1) != IS_NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ZVAL_COPY(result, op1);
|
||||
if (opcode == ZEND_PRE_INC
|
||||
@ -675,6 +680,11 @@ static inline zend_result ct_eval_incdec(zval *result, uint8_t opcode, zval *op1
|
||||
|| opcode == ZEND_POST_INC_OBJ) {
|
||||
increment_function(result);
|
||||
} else {
|
||||
/* Decrement on null emits a deprecation notice */
|
||||
if (Z_TYPE_P(op1) == IS_NULL) {
|
||||
zval_ptr_dtor(result);
|
||||
return FAILURE;
|
||||
}
|
||||
decrement_function(result);
|
||||
}
|
||||
return SUCCESS;
|
||||
@ -1375,21 +1385,22 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
|
||||
&& ctx->scdf.ssa->vars[ssa_op->op1_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
|
||||
zval tmp1, tmp2;
|
||||
|
||||
if (ct_eval_fetch_obj(&tmp1, op1, op2) == SUCCESS
|
||||
&& ct_eval_incdec(&tmp2, opline->opcode, &tmp1) == SUCCESS) {
|
||||
|
||||
dup_partial_object(&zv, op1);
|
||||
ct_eval_assign_obj(&zv, &tmp2, op2);
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
|
||||
SET_RESULT(result, &tmp2);
|
||||
} else {
|
||||
SET_RESULT(result, &tmp1);
|
||||
if (ct_eval_fetch_obj(&tmp1, op1, op2) == SUCCESS) {
|
||||
if (ct_eval_incdec(&tmp2, opline->opcode, &tmp1) == SUCCESS) {
|
||||
dup_partial_object(&zv, op1);
|
||||
ct_eval_assign_obj(&zv, &tmp2, op2);
|
||||
if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
|
||||
SET_RESULT(result, &tmp2);
|
||||
} else {
|
||||
SET_RESULT(result, &tmp1);
|
||||
}
|
||||
zval_ptr_dtor_nogc(&tmp1);
|
||||
zval_ptr_dtor_nogc(&tmp2);
|
||||
SET_RESULT(op1, &zv);
|
||||
zval_ptr_dtor_nogc(&zv);
|
||||
break;
|
||||
}
|
||||
zval_ptr_dtor_nogc(&tmp1);
|
||||
zval_ptr_dtor_nogc(&tmp2);
|
||||
SET_RESULT(op1, &zv);
|
||||
zval_ptr_dtor_nogc(&zv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2109,7 +2120,7 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var,
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we cannot remove instruction that defines other variables */
|
||||
return 0;
|
||||
|
@ -4681,9 +4681,11 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
|
||||
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
|
||||
case ZEND_PRE_INC:
|
||||
case ZEND_POST_INC:
|
||||
return (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
|
||||
/* null emits a warning as it has no effect compared to ++ which converts the value to 1 */
|
||||
case ZEND_PRE_DEC:
|
||||
case ZEND_POST_DEC:
|
||||
return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
|
||||
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
|
||||
case ZEND_BOOL_NOT:
|
||||
case ZEND_JMPZ:
|
||||
case ZEND_JMPNZ:
|
||||
|
@ -1,67 +0,0 @@
|
||||
--TEST--
|
||||
decrementing different variables
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = array(
|
||||
array(1,2,3),
|
||||
"",
|
||||
1,
|
||||
2.5,
|
||||
0,
|
||||
"string",
|
||||
"123",
|
||||
"2.5",
|
||||
NULL,
|
||||
true,
|
||||
false,
|
||||
new stdclass,
|
||||
array(),
|
||||
-PHP_INT_MAX-1,
|
||||
(string)(-PHP_INT_MAX-1),
|
||||
);
|
||||
|
||||
foreach ($a as $var) {
|
||||
try {
|
||||
$var--;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Cannot decrement array
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
int(-1)
|
||||
int(0)
|
||||
float(1.5)
|
||||
int(-1)
|
||||
string(6) "string"
|
||||
int(122)
|
||||
float(1.5)
|
||||
NULL
|
||||
bool(true)
|
||||
bool(false)
|
||||
Cannot decrement stdClass
|
||||
object(stdClass)#%d (0) {
|
||||
}
|
||||
Cannot decrement array
|
||||
array(0) {
|
||||
}
|
||||
float(-2147483649)
|
||||
float(-2147483649)
|
||||
Done
|
@ -1,67 +0,0 @@
|
||||
--TEST--
|
||||
decrementing different variables
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = array(
|
||||
array(1,2,3),
|
||||
"",
|
||||
1,
|
||||
2.5,
|
||||
0,
|
||||
"string",
|
||||
"123",
|
||||
"2.5",
|
||||
NULL,
|
||||
true,
|
||||
false,
|
||||
new stdclass,
|
||||
array(),
|
||||
-PHP_INT_MAX-1,
|
||||
(string)(-PHP_INT_MAX-1),
|
||||
);
|
||||
|
||||
foreach ($a as $var) {
|
||||
try {
|
||||
$var--;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot decrement array
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
int(-1)
|
||||
int(0)
|
||||
float(1.5)
|
||||
int(-1)
|
||||
string(6) "string"
|
||||
int(122)
|
||||
float(1.5)
|
||||
NULL
|
||||
bool(true)
|
||||
bool(false)
|
||||
Cannot decrement stdClass
|
||||
object(stdClass)#1 (0) {
|
||||
}
|
||||
Cannot decrement array
|
||||
array(0) {
|
||||
}
|
||||
float(-9.223372036854776E+18)
|
||||
float(-9.223372036854776E+18)
|
||||
Done
|
25
Zend/tests/in-de-crement/decrement_001.phpt
Normal file
25
Zend/tests/in-de-crement/decrement_001.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Decrementing min int values 32bit
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$values = [
|
||||
-PHP_INT_MAX-1,
|
||||
(string)(-PHP_INT_MAX-1),
|
||||
];
|
||||
|
||||
foreach ($values as $var) {
|
||||
$var--;
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
float(-2147483649)
|
||||
float(-2147483649)
|
||||
Done
|
25
Zend/tests/in-de-crement/decrement_001_64bit.phpt
Normal file
25
Zend/tests/in-de-crement/decrement_001_64bit.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Decrementing min int values 64bit
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$values = [
|
||||
-PHP_INT_MAX-1,
|
||||
(string)(-PHP_INT_MAX-1),
|
||||
];
|
||||
|
||||
foreach ($values as $var) {
|
||||
$var--;
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
float(-9.223372036854776E+18)
|
||||
float(-9.223372036854776E+18)
|
||||
Done
|
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Error handler can change type of operand of --
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function () {
|
||||
global $x;
|
||||
$x = 1;
|
||||
});
|
||||
|
||||
$x = '';
|
||||
$x--;
|
||||
var_dump($x);
|
||||
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
int(-1)
|
||||
DONE
|
@ -0,0 +1,76 @@
|
||||
--TEST--
|
||||
Decrementing objects which are castable to numeric types
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$l = new LongCastableNoOperations(5);
|
||||
$f = new FloatCastableNoOperations(15.8);
|
||||
$nl = new NumericCastableNoOperations(52);
|
||||
$nf = new NumericCastableNoOperations(58.3);
|
||||
|
||||
/* Check normal arithmetic */
|
||||
try {
|
||||
var_dump($l - 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($f - 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($nl - 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($nf - 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
/* Decrement */
|
||||
try {
|
||||
$l--;
|
||||
var_dump($l);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$f--;
|
||||
var_dump($f);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$nl--;
|
||||
var_dump($nl);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$nf--;
|
||||
var_dump($nf);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Unsupported operand types: LongCastableNoOperations - int
|
||||
Unsupported operand types: FloatCastableNoOperations - int
|
||||
int(51)
|
||||
float(57.3)
|
||||
Cannot decrement LongCastableNoOperations
|
||||
Cannot decrement FloatCastableNoOperations
|
||||
int(51)
|
||||
float(57.3)
|
28
Zend/tests/in-de-crement/incdec_bool_exception.phpt
Normal file
28
Zend/tests/in-de-crement/incdec_bool_exception.phpt
Normal file
@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
Inc/dec on bool: warning converted to exception
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function($severity, $m) {
|
||||
throw new Exception($m, $severity);
|
||||
});
|
||||
|
||||
$values = [false, true];
|
||||
foreach ($values as $value) {
|
||||
try {
|
||||
$value++;
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
try {
|
||||
$value--;
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Increment on type bool has no effect, this will change in the next major version of PHP
|
||||
Decrement on type bool has no effect, this will change in the next major version of PHP
|
||||
Increment on type bool has no effect, this will change in the next major version of PHP
|
||||
Decrement on type bool has no effect, this will change in the next major version of PHP
|
126
Zend/tests/in-de-crement/incdec_strings.phpt
Normal file
126
Zend/tests/in-de-crement/incdec_strings.phpt
Normal file
@ -0,0 +1,126 @@
|
||||
--TEST--
|
||||
Inc/dec various strings
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
echo "Using increment:\n";
|
||||
$values = [
|
||||
'',
|
||||
' ',
|
||||
// Numeric-ish values
|
||||
'0',
|
||||
'15.5',
|
||||
'1e10',
|
||||
// Alphanumeric values
|
||||
'199A',
|
||||
'A199',
|
||||
'199Z',
|
||||
'Z199',
|
||||
// Strings
|
||||
'Hello world',
|
||||
'🐘'
|
||||
];
|
||||
foreach ($values as $value) {
|
||||
echo "Initial value:";
|
||||
var_dump($value);
|
||||
$value++;
|
||||
echo "Result value:";
|
||||
var_dump($value);
|
||||
}
|
||||
|
||||
echo "Using decrement:\n";
|
||||
$values = [
|
||||
'',
|
||||
' ',
|
||||
// Numeric-ish values
|
||||
'0',
|
||||
'15.5',
|
||||
'1e10',
|
||||
// Alphanumeric values
|
||||
'199A',
|
||||
'A199',
|
||||
'199Z',
|
||||
'Z199',
|
||||
// Strings
|
||||
'Hello world',
|
||||
'🐘'
|
||||
];
|
||||
foreach ($values as $value) {
|
||||
echo "Initial value:";
|
||||
var_dump($value);
|
||||
$value--;
|
||||
echo "Result value:";
|
||||
var_dump($value);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Using increment:
|
||||
Initial value:string(0) ""
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(1) "1"
|
||||
Initial value:string(1) " "
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(1) " "
|
||||
Initial value:string(1) "0"
|
||||
Result value:int(1)
|
||||
Initial value:string(4) "15.5"
|
||||
Result value:float(16.5)
|
||||
Initial value:string(4) "1e10"
|
||||
Result value:float(10000000001)
|
||||
Initial value:string(4) "199A"
|
||||
Result value:string(4) "199B"
|
||||
Initial value:string(4) "A199"
|
||||
Result value:string(4) "A200"
|
||||
Initial value:string(4) "199Z"
|
||||
Result value:string(4) "200A"
|
||||
Initial value:string(4) "Z199"
|
||||
Result value:string(4) "Z200"
|
||||
Initial value:string(11) "Hello world"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(11) "Hello worle"
|
||||
Initial value:string(4) "🐘"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(4) "🐘"
|
||||
Using decrement:
|
||||
Initial value:string(0) ""
|
||||
|
||||
Deprecated: Decrement on empty string is deprecated as non-numeric in %s on line %d
|
||||
Result value:int(-1)
|
||||
Initial value:string(1) " "
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(1) " "
|
||||
Initial value:string(1) "0"
|
||||
Result value:int(-1)
|
||||
Initial value:string(4) "15.5"
|
||||
Result value:float(14.5)
|
||||
Initial value:string(4) "1e10"
|
||||
Result value:float(9999999999)
|
||||
Initial value:string(4) "199A"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(4) "199A"
|
||||
Initial value:string(4) "A199"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(4) "A199"
|
||||
Initial value:string(4) "199Z"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(4) "199Z"
|
||||
Initial value:string(4) "Z199"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(4) "Z199"
|
||||
Initial value:string(11) "Hello world"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(11) "Hello world"
|
||||
Initial value:string(4) "🐘"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(4) "🐘"
|
71
Zend/tests/in-de-crement/incdec_strings_exception.phpt
Normal file
71
Zend/tests/in-de-crement/incdec_strings_exception.phpt
Normal file
@ -0,0 +1,71 @@
|
||||
--TEST--
|
||||
Inc/dec on string: warning/deprecations converted to exception
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function($severity, $m) {
|
||||
if ($severity == E_DEPRECATED) {
|
||||
$m = 'Deprecated: ' . $m;
|
||||
}
|
||||
if ($severity == E_WARNING) {
|
||||
$m = 'Warning: ' . $m;
|
||||
}
|
||||
throw new Exception($m, $severity);
|
||||
});
|
||||
|
||||
$values = [
|
||||
'',
|
||||
' ',
|
||||
// Alphanumeric values
|
||||
'199A',
|
||||
'A199',
|
||||
'199Z',
|
||||
'Z199',
|
||||
// Strings
|
||||
'Hello world',
|
||||
'🐘'
|
||||
];
|
||||
foreach ($values as $value) {
|
||||
try {
|
||||
$value++;
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
var_dump($value);
|
||||
try {
|
||||
$value--;
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
var_dump($value);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated
|
||||
string(0) ""
|
||||
Deprecated: Decrement on empty string is deprecated as non-numeric
|
||||
string(0) ""
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated
|
||||
string(1) " "
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(1) " "
|
||||
string(4) "199B"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(4) "199B"
|
||||
string(4) "A200"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(4) "A200"
|
||||
string(4) "200A"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(4) "200A"
|
||||
string(4) "Z200"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(4) "Z200"
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated
|
||||
string(11) "Hello world"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(11) "Hello world"
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated
|
||||
string(4) "🐘"
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated
|
||||
string(4) "🐘"
|
100
Zend/tests/in-de-crement/incdec_types.phpt
Normal file
100
Zend/tests/in-de-crement/incdec_types.phpt
Normal file
@ -0,0 +1,100 @@
|
||||
--TEST--
|
||||
Inc/dec various types
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
/* Type errors */
|
||||
$types = [[], new stdClass(), fopen(__FILE__, 'r')];
|
||||
|
||||
foreach ($types as $type) {
|
||||
try {
|
||||
$type++;
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
try {
|
||||
$type--;
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
echo "Using increment:\n";
|
||||
$values = [null, false, true, 0, 0.0, '', ' ', '0'];
|
||||
foreach ($values as $value) {
|
||||
echo "Initial value:";
|
||||
var_dump($value);
|
||||
$value++;
|
||||
echo "Result value:";
|
||||
var_dump($value);
|
||||
}
|
||||
|
||||
echo "Using decrement:\n";
|
||||
$values = [null, false, true, 0, 0.0, '', ' ', '0'];
|
||||
foreach ($values as $value) {
|
||||
echo "Initial value:";
|
||||
var_dump($value);
|
||||
$value--;
|
||||
echo "Result value:";
|
||||
var_dump($value);
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Cannot increment array
|
||||
Cannot decrement array
|
||||
Cannot increment stdClass
|
||||
Cannot decrement stdClass
|
||||
Cannot increment resource
|
||||
Cannot decrement resource
|
||||
Using increment:
|
||||
Initial value:NULL
|
||||
Result value:int(1)
|
||||
Initial value:bool(false)
|
||||
|
||||
Warning: Increment on type bool has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
Result value:bool(false)
|
||||
Initial value:bool(true)
|
||||
|
||||
Warning: Increment on type bool has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
Result value:bool(true)
|
||||
Initial value:int(0)
|
||||
Result value:int(1)
|
||||
Initial value:float(0)
|
||||
Result value:float(1)
|
||||
Initial value:string(0) ""
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(1) "1"
|
||||
Initial value:string(1) " "
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
Result value:string(1) " "
|
||||
Initial value:string(1) "0"
|
||||
Result value:int(1)
|
||||
Using decrement:
|
||||
Initial value:NULL
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
Result value:NULL
|
||||
Initial value:bool(false)
|
||||
|
||||
Warning: Decrement on type bool has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
Result value:bool(false)
|
||||
Initial value:bool(true)
|
||||
|
||||
Warning: Decrement on type bool has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
Result value:bool(true)
|
||||
Initial value:int(0)
|
||||
Result value:int(-1)
|
||||
Initial value:float(0)
|
||||
Result value:float(-1)
|
||||
Initial value:string(0) ""
|
||||
|
||||
Deprecated: Decrement on empty string is deprecated as non-numeric in %s on line %d
|
||||
Result value:int(-1)
|
||||
Initial value:string(1) " "
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
Result value:string(1) " "
|
||||
Initial value:string(1) "0"
|
||||
Result value:int(-1)
|
@ -4,7 +4,6 @@ Inc/dec undef var with error handler
|
||||
<?php
|
||||
set_error_handler(function($_, $m) {
|
||||
echo "$m\n";
|
||||
unset($GLOBALS['x']);
|
||||
});
|
||||
var_dump($x--);
|
||||
unset($x);
|
||||
@ -16,10 +15,12 @@ var_dump(++$x);
|
||||
?>
|
||||
--EXPECT--
|
||||
Undefined variable $x
|
||||
Decrement on type null has no effect, this will change in the next major version of PHP
|
||||
NULL
|
||||
Undefined variable $x
|
||||
NULL
|
||||
Undefined variable $x
|
||||
Decrement on type null has no effect, this will change in the next major version of PHP
|
||||
NULL
|
||||
Undefined variable $x
|
||||
int(1)
|
24
Zend/tests/in-de-crement/increment_001.phpt
Normal file
24
Zend/tests/in-de-crement/increment_001.phpt
Normal file
@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Incrementing max int values 32bit
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$values = [
|
||||
PHP_INT_MAX,
|
||||
(string)PHP_INT_MAX
|
||||
];
|
||||
|
||||
foreach ($values as $var) {
|
||||
$var++;
|
||||
var_dump($var);
|
||||
}
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
float(2147483648)
|
||||
float(2147483648)
|
||||
Done
|
24
Zend/tests/in-de-crement/increment_001_64bit.phpt
Normal file
24
Zend/tests/in-de-crement/increment_001_64bit.phpt
Normal file
@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Incrementing max int values 64bit
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$values = [
|
||||
PHP_INT_MAX,
|
||||
(string)PHP_INT_MAX
|
||||
];
|
||||
|
||||
foreach ($values as $var) {
|
||||
$var++;
|
||||
var_dump($var);
|
||||
}
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
float(9.223372036854776E+18)
|
||||
float(9.223372036854776E+18)
|
||||
Done
|
@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
Error handler can change type of operand of ++
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function () {
|
||||
global $x;
|
||||
$x = 1;
|
||||
});
|
||||
|
||||
$x = '';
|
||||
$x++;
|
||||
var_dump($x);
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
var_dump($errstr);
|
||||
global $x;
|
||||
$x = new stdClass;
|
||||
});
|
||||
|
||||
$x = 'foo!';
|
||||
$x++;
|
||||
var_dump($x);
|
||||
|
||||
/* Interned string */
|
||||
$x = '!';
|
||||
$x++;
|
||||
var_dump($x);
|
||||
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
string(1) "1"
|
||||
string(50) "Increment on non-alphanumeric string is deprecated"
|
||||
string(4) "foo!"
|
||||
string(50) "Increment on non-alphanumeric string is deprecated"
|
||||
string(1) "!"
|
||||
DONE
|
@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Error handler can change type of operand of ++ to object with do_operator
|
||||
--EXTENSIONS--
|
||||
gmp
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
set_error_handler(function ($errno, $errstr) {
|
||||
var_dump($errstr);
|
||||
global $x;
|
||||
$x = gmp_init(10);
|
||||
});
|
||||
|
||||
$x = 'foo!';
|
||||
$x++;
|
||||
var_dump($x);
|
||||
|
||||
/* Interned string */
|
||||
$x = '!';
|
||||
$x++;
|
||||
var_dump($x);
|
||||
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
string(50) "Increment on non-alphanumeric string is deprecated"
|
||||
string(4) "foo!"
|
||||
string(50) "Increment on non-alphanumeric string is deprecated"
|
||||
string(1) "!"
|
||||
DONE
|
@ -0,0 +1,76 @@
|
||||
--TEST--
|
||||
Incrementing objects which are castable to numeric types
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$l = new LongCastableNoOperations(5);
|
||||
$f = new FloatCastableNoOperations(15.8);
|
||||
$nl = new NumericCastableNoOperations(52);
|
||||
$nf = new NumericCastableNoOperations(58.3);
|
||||
|
||||
/* Check normal arithmetic */
|
||||
try {
|
||||
var_dump($l + 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($f + 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($nl + 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump($nf + 1);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
/* Decrement */
|
||||
try {
|
||||
$l++;
|
||||
var_dump($l);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$f++;
|
||||
var_dump($f);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$nl++;
|
||||
var_dump($nl);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
try {
|
||||
$nf++;
|
||||
var_dump($nf);
|
||||
} catch (\TypeError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Unsupported operand types: LongCastableNoOperations + int
|
||||
Unsupported operand types: FloatCastableNoOperations + int
|
||||
int(53)
|
||||
float(59.3)
|
||||
Cannot increment LongCastableNoOperations
|
||||
Cannot increment FloatCastableNoOperations
|
||||
int(53)
|
||||
float(59.3)
|
107
Zend/tests/in-de-crement/string_increment_various.phpt
Normal file
107
Zend/tests/in-de-crement/string_increment_various.phpt
Normal file
@ -0,0 +1,107 @@
|
||||
--TEST--
|
||||
String increment on a variety of strings
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strictlyAlphaNumeric = [
|
||||
"Az",
|
||||
"aZ",
|
||||
"A9",
|
||||
"a9",
|
||||
// Carrying values until the beginning of the string
|
||||
"Zz",
|
||||
"zZ",
|
||||
"9z",
|
||||
"9Z",
|
||||
];
|
||||
|
||||
$strings = [
|
||||
// Empty string
|
||||
"",
|
||||
// String increments are unaware of being "negative"
|
||||
"-cc",
|
||||
// Trailing whitespace
|
||||
"Z ",
|
||||
// Leading whitespace
|
||||
" Z",
|
||||
// Non-ASCII characters
|
||||
"é",
|
||||
"あいうえお",
|
||||
"α",
|
||||
"ω",
|
||||
"Α",
|
||||
"Ω",
|
||||
// With period
|
||||
"foo1.txt",
|
||||
"1f.5",
|
||||
// With multiple period
|
||||
"foo.1.txt",
|
||||
"1.f.5",
|
||||
];
|
||||
|
||||
foreach ($strictlyAlphaNumeric as $s) {
|
||||
var_dump(++$s);
|
||||
}
|
||||
foreach ($strings as $s) {
|
||||
var_dump(++$s);
|
||||
}
|
||||
|
||||
// Will get converted to float on the second increment as it gets changed to a
|
||||
// string interpretable as a number in scientific notation
|
||||
$s = "5d9";
|
||||
var_dump(++$s); // string(3) "5e0"
|
||||
var_dump(++$s); // float(6)
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(2) "Ba"
|
||||
string(2) "bA"
|
||||
string(2) "B0"
|
||||
string(2) "b0"
|
||||
string(3) "AAa"
|
||||
string(3) "aaA"
|
||||
string(3) "10a"
|
||||
string(3) "10A"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(1) "1"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(3) "-cd"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "Z "
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) " A"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "é"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(15) "あいうえお"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "α"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "ω"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "Α"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(2) "Ω"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(8) "foo1.txu"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(4) "1f.6"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(9) "foo.1.txu"
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(5) "1.f.6"
|
||||
string(3) "5e0"
|
||||
float(6)
|
@ -1,67 +0,0 @@
|
||||
--TEST--
|
||||
incrementing different variables
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only"); ?>
|
||||
--INI--
|
||||
precision=14
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = array(
|
||||
array(1,2,3),
|
||||
"",
|
||||
1,
|
||||
2.5,
|
||||
0,
|
||||
"string",
|
||||
"123",
|
||||
"2.5",
|
||||
NULL,
|
||||
true,
|
||||
false,
|
||||
new stdclass,
|
||||
array(),
|
||||
PHP_INT_MAX,
|
||||
(string)PHP_INT_MAX
|
||||
);
|
||||
|
||||
foreach ($a as $var) {
|
||||
try {
|
||||
$var++;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($var);
|
||||
}
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Cannot increment array
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
string(1) "1"
|
||||
int(2)
|
||||
float(3.5)
|
||||
int(1)
|
||||
string(6) "strinh"
|
||||
int(124)
|
||||
float(3.5)
|
||||
int(1)
|
||||
bool(true)
|
||||
bool(false)
|
||||
Cannot increment stdClass
|
||||
object(stdClass)#%d (0) {
|
||||
}
|
||||
Cannot increment array
|
||||
array(0) {
|
||||
}
|
||||
float(2147483648)
|
||||
float(2147483648)
|
||||
Done
|
@ -2105,4 +2105,5 @@ Cannot decrement stdClass
|
||||
Cannot increment resource
|
||||
Cannot decrement resource
|
||||
No error for fop++
|
||||
Warning: Decrement on non-numeric string has no effect and is deprecated
|
||||
No error for foo--
|
||||
|
@ -12,3 +12,5 @@ test();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Undefined variable $n in %s on line %d
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
|
@ -13,3 +13,5 @@ test();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Undefined variable $i in %s on line %d
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
|
@ -2493,7 +2493,20 @@ ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *ins
|
||||
#define UPPER_CASE 2
|
||||
#define NUMERIC 3
|
||||
|
||||
static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
|
||||
ZEND_API bool zend_string_only_has_ascii_alphanumeric(const zend_string *str)
|
||||
{
|
||||
const char *p = ZSTR_VAL(str);
|
||||
const char *e = ZSTR_VAL(str) + ZSTR_LEN(str);
|
||||
while (p < e) {
|
||||
char c = *p++;
|
||||
if (UNEXPECTED( c < '0' || c > 'z' || (c < 'a' && c > 'Z') || (c < 'A' && c > '9') ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ZEND_FASTCALL increment_string(zval *str) /* {{{ */
|
||||
{
|
||||
int carry=0;
|
||||
size_t pos=Z_STRLEN_P(str)-1;
|
||||
@ -2502,10 +2515,30 @@ static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
|
||||
int last=0; /* Shut up the compiler warning */
|
||||
int ch;
|
||||
|
||||
if (Z_STRLEN_P(str) == 0) {
|
||||
zval_ptr_dtor_str(str);
|
||||
if (UNEXPECTED(Z_STRLEN_P(str) == 0)) {
|
||||
zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
|
||||
if (EG(exception)) {
|
||||
return false;
|
||||
}
|
||||
/* A userland error handler can change the type from string to something else */
|
||||
zval_ptr_dtor(str);
|
||||
ZVAL_CHAR(str, '1');
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UNEXPECTED(!zend_string_only_has_ascii_alphanumeric(Z_STR_P(str)))) {
|
||||
zend_string *zstr = Z_STR_P(str);
|
||||
GC_TRY_ADDREF(zstr);
|
||||
zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
|
||||
if (EG(exception)) {
|
||||
GC_TRY_DELREF(zstr);
|
||||
if (!GC_REFCOUNT(zstr)) {
|
||||
efree(zstr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
zval_ptr_dtor(str);
|
||||
ZVAL_STR(str, zstr);
|
||||
}
|
||||
|
||||
if (!Z_REFCOUNTED_P(str)) {
|
||||
@ -2577,6 +2610,7 @@ static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
|
||||
zend_string_free(Z_STR_P(str));
|
||||
ZVAL_NEW_STR(str, t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@ -2615,18 +2649,21 @@ try_again:
|
||||
default:
|
||||
/* Perl style string increment */
|
||||
increment_string(op1);
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IS_FALSE:
|
||||
case IS_TRUE:
|
||||
/* Do nothing. */
|
||||
zend_error(E_WARNING, "Increment on type bool has no effect, this will change in the next major version of PHP");
|
||||
break;
|
||||
case IS_REFERENCE:
|
||||
op1 = Z_REFVAL_P(op1);
|
||||
goto try_again;
|
||||
case IS_OBJECT:
|
||||
case IS_OBJECT: {
|
||||
if (Z_OBJ_HANDLER_P(op1, do_operation)) {
|
||||
zval op2;
|
||||
ZVAL_LONG(&op2, 1);
|
||||
@ -2634,7 +2671,15 @@ try_again:
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
zval tmp;
|
||||
if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
|
||||
ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
|
||||
zval_ptr_dtor(op1);
|
||||
ZVAL_COPY_VALUE(op1, &tmp);
|
||||
goto try_again;
|
||||
}
|
||||
ZEND_FALLTHROUGH;
|
||||
}
|
||||
case IS_RESOURCE:
|
||||
case IS_ARRAY:
|
||||
zend_type_error("Cannot increment %s", zend_zval_value_name(op1));
|
||||
@ -2660,7 +2705,12 @@ try_again:
|
||||
break;
|
||||
case IS_STRING: /* Like perl we only support string increment */
|
||||
if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
|
||||
zval_ptr_dtor_str(op1);
|
||||
zend_error(E_DEPRECATED, "Decrement on empty string is deprecated as non-numeric");
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
/* A userland error handler can change the type from string to something else */
|
||||
zval_ptr_dtor(op1);
|
||||
ZVAL_LONG(op1, -1);
|
||||
break;
|
||||
}
|
||||
@ -2678,17 +2728,30 @@ try_again:
|
||||
zval_ptr_dtor_str(op1);
|
||||
ZVAL_DOUBLE(op1, dval - 1);
|
||||
break;
|
||||
default:
|
||||
zend_error(E_DEPRECATED, "Decrement on non-numeric string has no effect and is deprecated");
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IS_NULL:
|
||||
zend_error(E_WARNING, "Decrement on type null has no effect, this will change in the next major version of PHP");
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
break;
|
||||
case IS_FALSE:
|
||||
case IS_TRUE:
|
||||
/* Do nothing. */
|
||||
zend_error(E_WARNING, "Decrement on type bool has no effect, this will change in the next major version of PHP");
|
||||
if (EG(exception)) {
|
||||
return FAILURE;
|
||||
}
|
||||
break;
|
||||
case IS_REFERENCE:
|
||||
op1 = Z_REFVAL_P(op1);
|
||||
goto try_again;
|
||||
case IS_OBJECT:
|
||||
case IS_OBJECT: {
|
||||
if (Z_OBJ_HANDLER_P(op1, do_operation)) {
|
||||
zval op2;
|
||||
ZVAL_LONG(&op2, 1);
|
||||
@ -2696,7 +2759,15 @@ try_again:
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
zval tmp;
|
||||
if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
|
||||
ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
|
||||
zval_ptr_dtor(op1);
|
||||
ZVAL_COPY_VALUE(op1, &tmp);
|
||||
goto try_again;
|
||||
}
|
||||
ZEND_FALLTHROUGH;
|
||||
}
|
||||
case IS_RESOURCE:
|
||||
case IS_ARRAY:
|
||||
zend_type_error("Cannot decrement %s", zend_zval_value_name(op1));
|
||||
|
@ -72,6 +72,8 @@ static zend_always_inline bool instanceof_function(
|
||||
return instance_ce == ce || instanceof_function_slow(instance_ce, ce);
|
||||
}
|
||||
|
||||
ZEND_API bool zend_string_only_has_ascii_alphanumeric(const zend_string *str);
|
||||
|
||||
/**
|
||||
* Checks whether the string "str" with length "length" is numeric. The value
|
||||
* of allow_errors determines whether it's required to be entirely numeric, or
|
||||
|
@ -1500,6 +1500,9 @@ ZEND_VM_HELPER(zend_pre_inc_helper, VAR|CV, ANY)
|
||||
}
|
||||
}
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -1552,6 +1555,9 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY)
|
||||
}
|
||||
}
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -1606,6 +1612,9 @@ ZEND_VM_HELPER(zend_post_inc_helper, VAR|CV, ANY)
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
FREE_OP1();
|
||||
@ -1654,6 +1663,9 @@ ZEND_VM_HELPER(zend_post_dec_helper, VAR|CV, ANY)
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
FREE_OP1();
|
||||
|
24
Zend/zend_vm_execute.h
generated
24
Zend/zend_vm_execute.h
generated
@ -21615,6 +21615,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_inc_help
|
||||
}
|
||||
}
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -21685,6 +21688,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_dec_help
|
||||
}
|
||||
}
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -21757,6 +21763,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_post_inc_hel
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
|
||||
@ -21805,6 +21814,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_post_dec_hel
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
|
||||
@ -38974,6 +38986,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_inc_help
|
||||
}
|
||||
}
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -39043,6 +39058,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_pre_dec_help
|
||||
}
|
||||
}
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
@ -39114,6 +39132,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_post_inc_hel
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
increment_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
@ -39161,6 +39182,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_post_dec_hel
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
|
||||
|
||||
decrement_function(var_ptr);
|
||||
if (UNEXPECTED(EG(exception))) {
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
} while (0);
|
||||
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
|
@ -19,4 +19,6 @@ myfunc();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Undefined variable $x in %s on line %d
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d
|
||||
'2' is expected to be 2
|
||||
|
@ -17,5 +17,6 @@ function foo() {
|
||||
}
|
||||
var_dump(foo());
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Warning: Increment on type bool has no effect, this will change in the next major version of PHP in %sinc_017.php on line 4
|
||||
bool(true)
|
||||
|
@ -17,5 +17,6 @@ function foo() {
|
||||
}
|
||||
var_dump(foo());
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Warning: Increment on type bool has no effect, this will change in the next major version of PHP in %sinc_018.php on line 4
|
||||
bool(false)
|
||||
|
@ -19,6 +19,9 @@ $test->prop = "a";
|
||||
var_dump(++$test->prop);
|
||||
var_dump(--$test->prop);
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
string(1) "c"
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
string(1) "c"
|
||||
|
@ -23,6 +23,53 @@ function test($b) {
|
||||
}
|
||||
test("0");
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated in %s on line %d
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(5) "-INF0"
|
||||
string(260) "0-2-12-112-1112-11112-111112-1111112-11111112-111111112-1111111112-11111111112-111111111112-1111111111112-11111111111112-111111111111112-1111111111111112-11111111111111112-111111111111111112-1111111111111111112-1.1111111111111E+20-1.1111111111111E+191-ING-INF1"
|
||||
|
@ -18,4 +18,8 @@ foo();
|
||||
DONE
|
||||
--EXPECTF--
|
||||
Warning: Undefined variable $a in %sreg_alloc_014.php on line 4
|
||||
DONE
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %sreg_alloc_014.php on line 4
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %sreg_alloc_014.php on line 4
|
||||
DONE
|
||||
|
@ -13,11 +13,13 @@ function test() {
|
||||
}
|
||||
}
|
||||
try {
|
||||
@test();
|
||||
test();
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
NULL
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %sinference_016.php on line %d
|
||||
Modulo by zero
|
||||
|
@ -18,5 +18,7 @@ function test() {
|
||||
test();
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
|
||||
Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %sinference_019.php on line %d
|
||||
DONE
|
||||
|
@ -14,5 +14,6 @@ function foo() {
|
||||
foo();
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %ssccp_038.php on line 5
|
||||
DONE
|
||||
|
@ -23,8 +23,8 @@ class F extends E {
|
||||
static protected $prop;
|
||||
}
|
||||
|
||||
$class = 'A';
|
||||
for($class = 'A'; $class <= 'F'; $class ++) {
|
||||
$classes = ['A', 'B', 'C', 'D', 'E', 'F'];
|
||||
foreach ($classes as $class) {
|
||||
print($class.' => ');
|
||||
try {
|
||||
$rp = new ReflectionProperty($class, 'prop');
|
||||
|
@ -9,7 +9,8 @@ class C1 { }
|
||||
class C2 { use T1; }
|
||||
class C3 { use T1; use T2; }
|
||||
|
||||
for ($c = "C1"; $c <= "C3"; $c++) {
|
||||
$classes = ['C1', 'C2', 'C3'];
|
||||
foreach ($classes as $c) {
|
||||
echo "class $c:\n";
|
||||
$r = new ReflectionClass($c);
|
||||
var_dump($r->getTraitNames());
|
||||
|
@ -9,7 +9,8 @@ class C2 { use T1; }
|
||||
class C3 { use T1 { m1 as a1; } }
|
||||
class C4 { use T1 { m1 as a1; m2 as a2; } }
|
||||
|
||||
for ($c = "C1"; $c <= "C4"; $c++) {
|
||||
$classes = ['C1', 'C2', 'C3', 'C4'];
|
||||
foreach ($classes as $c) {
|
||||
echo "class $c:\n";
|
||||
$r = new ReflectionClass($c);
|
||||
var_dump($r->getTraitAliases());
|
||||
|
@ -2348,6 +2348,10 @@ function strtoupper(string $string): string {}
|
||||
/** @compile-time-eval */
|
||||
function strtolower(string $string): string {}
|
||||
|
||||
function str_increment(string $string): string {}
|
||||
|
||||
function str_decrement(string $string): string {}
|
||||
|
||||
/** @refcount 1 */
|
||||
function basename(string $path, string $suffix = ""): string {}
|
||||
|
||||
|
10
ext/standard/basic_functions_arginfo.h
generated
10
ext/standard/basic_functions_arginfo.h
generated
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: a15bbbd1d29dfd674dd2174b3be5678a0832116a */
|
||||
* Stub hash: e01f6a979e72b1c3baf4602421cc966edfe50312 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
@ -872,6 +872,10 @@ ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_strtolower arginfo_base64_encode
|
||||
|
||||
#define arginfo_str_increment arginfo_base64_encode
|
||||
|
||||
#define arginfo_str_decrement arginfo_base64_encode
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_basename, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, suffix, IS_STRING, 0, "\"\"")
|
||||
@ -2447,6 +2451,8 @@ ZEND_FUNCTION(implode);
|
||||
ZEND_FUNCTION(strtok);
|
||||
ZEND_FUNCTION(strtoupper);
|
||||
ZEND_FUNCTION(strtolower);
|
||||
ZEND_FUNCTION(str_increment);
|
||||
ZEND_FUNCTION(str_decrement);
|
||||
ZEND_FUNCTION(basename);
|
||||
ZEND_FUNCTION(dirname);
|
||||
ZEND_FUNCTION(pathinfo);
|
||||
@ -3081,6 +3087,8 @@ static const zend_function_entry ext_functions[] = {
|
||||
ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtok, arginfo_strtok)
|
||||
ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtoupper, arginfo_strtoupper)
|
||||
ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtolower, arginfo_strtolower)
|
||||
ZEND_FE(str_increment, arginfo_str_increment)
|
||||
ZEND_FE(str_decrement, arginfo_str_decrement)
|
||||
ZEND_FE(basename, arginfo_basename)
|
||||
ZEND_FE(dirname, arginfo_dirname)
|
||||
ZEND_FE(pathinfo, arginfo_pathinfo)
|
||||
|
@ -1192,6 +1192,118 @@ PHP_FUNCTION(strtolower)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHP_FUNCTION(str_increment)
|
||||
{
|
||||
zend_string *str;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(str)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (ZSTR_LEN(str) == 0) {
|
||||
zend_argument_value_error(1, "cannot be empty");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
if (!zend_string_only_has_ascii_alphanumeric(str)) {
|
||||
zend_argument_value_error(1, "must be composed only of alphanumeric ASCII characters");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_string *incremented = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), /* persistent */ false);
|
||||
size_t position = ZSTR_LEN(str)-1;
|
||||
bool carry = false;
|
||||
|
||||
do {
|
||||
char c = ZSTR_VAL(incremented)[position];
|
||||
/* We know c is in ['a', 'z'], ['A', 'Z'], or ['0', '9'] range from zend_string_only_has_ascii_alphanumeric() */
|
||||
if (EXPECTED( c != 'z' && c != 'Z' && c != '9' )) {
|
||||
carry = false;
|
||||
ZSTR_VAL(incremented)[position]++;
|
||||
} else { /* if 'z', 'Z', or '9' */
|
||||
carry = true;
|
||||
if (c == '9') {
|
||||
ZSTR_VAL(incremented)[position] = '0';
|
||||
} else {
|
||||
ZSTR_VAL(incremented)[position] -= 25;
|
||||
}
|
||||
}
|
||||
} while (carry && position-- > 0);
|
||||
|
||||
if (UNEXPECTED(carry)) {
|
||||
zend_string *tmp = zend_string_alloc(ZSTR_LEN(incremented)+1, 0);
|
||||
memcpy(ZSTR_VAL(tmp) + 1, ZSTR_VAL(incremented), ZSTR_LEN(incremented));
|
||||
ZSTR_VAL(tmp)[ZSTR_LEN(incremented)+1] = '\0';
|
||||
switch (ZSTR_VAL(incremented)[0]) {
|
||||
case '0':
|
||||
ZSTR_VAL(tmp)[0] = '1';
|
||||
break;
|
||||
default:
|
||||
ZSTR_VAL(tmp)[0] = ZSTR_VAL(incremented)[0];
|
||||
break;
|
||||
}
|
||||
zend_string_release_ex(incremented, /* persistent */ false);
|
||||
RETURN_STR(tmp);
|
||||
}
|
||||
RETURN_STR(incremented);
|
||||
}
|
||||
|
||||
|
||||
PHP_FUNCTION(str_decrement)
|
||||
{
|
||||
zend_string *str;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(str)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (ZSTR_LEN(str) == 0) {
|
||||
zend_argument_value_error(1, "cannot be empty");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
if (!zend_string_only_has_ascii_alphanumeric(str)) {
|
||||
zend_argument_value_error(1, "must be composed only of alphanumeric ASCII characters");
|
||||
RETURN_THROWS();
|
||||
}
|
||||
if (ZSTR_LEN(str) >= 1 && ZSTR_VAL(str)[0] == '0') {
|
||||
zend_argument_value_error(1, "\"%s\" is out of decrement range", ZSTR_VAL(str));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
zend_string *decremented = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), /* persistent */ false);
|
||||
size_t position = ZSTR_LEN(str)-1;
|
||||
bool carry = false;
|
||||
|
||||
do {
|
||||
char c = ZSTR_VAL(decremented)[position];
|
||||
/* We know c is in ['a', 'z'], ['A', 'Z'], or ['0', '9'] range from zend_string_only_has_ascii_alphanumeric() */
|
||||
if (EXPECTED( c != 'a' && c != 'A' && c != '0' )) {
|
||||
carry = false;
|
||||
ZSTR_VAL(decremented)[position]--;
|
||||
} else { /* if 'a', 'A', or '0' */
|
||||
carry = true;
|
||||
if (c == '0') {
|
||||
ZSTR_VAL(decremented)[position] = '9';
|
||||
} else {
|
||||
ZSTR_VAL(decremented)[position] += 25;
|
||||
}
|
||||
}
|
||||
} while (carry && position-- > 0);
|
||||
|
||||
if (UNEXPECTED(carry || ZSTR_VAL(decremented)[0] == '0')) {
|
||||
if (ZSTR_LEN(decremented) == 1) {
|
||||
zend_string_release_ex(decremented, /* persistent */ false);
|
||||
zend_argument_value_error(1, "\"%s\" is out of decrement range", ZSTR_VAL(str));
|
||||
RETURN_THROWS();
|
||||
}
|
||||
zend_string *tmp = zend_string_alloc(ZSTR_LEN(decremented) - 1, 0);
|
||||
memcpy(ZSTR_VAL(tmp), ZSTR_VAL(decremented) + 1, ZSTR_LEN(decremented) - 1);
|
||||
ZSTR_VAL(tmp)[ZSTR_LEN(decremented) - 1] = '\0';
|
||||
zend_string_release_ex(decremented, /* persistent */ false);
|
||||
RETURN_STR(tmp);
|
||||
}
|
||||
RETURN_STR(decremented);
|
||||
}
|
||||
|
||||
#if defined(PHP_WIN32)
|
||||
static bool _is_basename_start(const char *start, const char *pos)
|
||||
{
|
||||
|
@ -2,121 +2,150 @@
|
||||
basic array_combine test
|
||||
--FILE--
|
||||
<?php
|
||||
$array1 = array('green', 'red', 'yellow');
|
||||
$array2 = array('1', '2', '3');
|
||||
$array3 = array(0, 1, 2);
|
||||
$array4 = array(TRUE, FALSE, NULL);
|
||||
$a = array_combine($array1, $array1);
|
||||
$b = array_combine($array1, $array2);
|
||||
$c = array_combine($array1, $array3);
|
||||
$d = array_combine($array1, $array4);
|
||||
$e = array_combine($array2, $array1);
|
||||
$f = array_combine($array2, $array2);
|
||||
$g = array_combine($array2, $array3);
|
||||
$h = array_combine($array2, $array4);
|
||||
$i = array_combine($array3, $array1);
|
||||
$j = array_combine($array3, $array2);
|
||||
$k = array_combine($array3, $array3);
|
||||
$l = array_combine($array3, $array4);
|
||||
$m = array_combine($array4, $array1);
|
||||
$n = array_combine($array4, $array2);
|
||||
$o = array_combine($array4, $array3);
|
||||
$p = array_combine($array4, $array4);
|
||||
for($letter = "a"; $letter <= "p"; $letter++)
|
||||
{
|
||||
print_r($$letter);
|
||||
}
|
||||
$array1 = array('green', 'red', 'yellow');
|
||||
$array2 = array('1', '2', '3');
|
||||
$array3 = array(0, 1, 2);
|
||||
$array4 = array(TRUE, FALSE, NULL);
|
||||
$a = array_combine($array1, $array1);
|
||||
$b = array_combine($array1, $array2);
|
||||
$c = array_combine($array1, $array3);
|
||||
$d = array_combine($array1, $array4);
|
||||
$e = array_combine($array2, $array1);
|
||||
$f = array_combine($array2, $array2);
|
||||
$g = array_combine($array2, $array3);
|
||||
$h = array_combine($array2, $array4);
|
||||
$i = array_combine($array3, $array1);
|
||||
$j = array_combine($array3, $array2);
|
||||
$k = array_combine($array3, $array3);
|
||||
$l = array_combine($array3, $array4);
|
||||
$m = array_combine($array4, $array1);
|
||||
$n = array_combine($array4, $array2);
|
||||
$o = array_combine($array4, $array3);
|
||||
$p = array_combine($array4, $array4);
|
||||
|
||||
$letters = range('a', 'p');
|
||||
foreach ($letters as $letter) {
|
||||
var_dump($$letter);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Array
|
||||
(
|
||||
[green] => green
|
||||
[red] => red
|
||||
[yellow] => yellow
|
||||
)
|
||||
Array
|
||||
(
|
||||
[green] => 1
|
||||
[red] => 2
|
||||
[yellow] => 3
|
||||
)
|
||||
Array
|
||||
(
|
||||
[green] => 0
|
||||
[red] => 1
|
||||
[yellow] => 2
|
||||
)
|
||||
Array
|
||||
(
|
||||
[green] => 1
|
||||
[red] =>
|
||||
[yellow] =>
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => green
|
||||
[2] => red
|
||||
[3] => yellow
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 1
|
||||
[2] => 2
|
||||
[3] => 3
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 0
|
||||
[2] => 1
|
||||
[3] => 2
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 1
|
||||
[2] =>
|
||||
[3] =>
|
||||
)
|
||||
Array
|
||||
(
|
||||
[0] => green
|
||||
[1] => red
|
||||
[2] => yellow
|
||||
)
|
||||
Array
|
||||
(
|
||||
[0] => 1
|
||||
[1] => 2
|
||||
[2] => 3
|
||||
)
|
||||
Array
|
||||
(
|
||||
[0] => 0
|
||||
[1] => 1
|
||||
[2] => 2
|
||||
)
|
||||
Array
|
||||
(
|
||||
[0] => 1
|
||||
[1] =>
|
||||
[2] =>
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => green
|
||||
[] => yellow
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 1
|
||||
[] => 3
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 0
|
||||
[] => 2
|
||||
)
|
||||
Array
|
||||
(
|
||||
[1] => 1
|
||||
[] =>
|
||||
)
|
||||
array(3) {
|
||||
["green"]=>
|
||||
string(5) "green"
|
||||
["red"]=>
|
||||
string(3) "red"
|
||||
["yellow"]=>
|
||||
string(6) "yellow"
|
||||
}
|
||||
array(3) {
|
||||
["green"]=>
|
||||
string(1) "1"
|
||||
["red"]=>
|
||||
string(1) "2"
|
||||
["yellow"]=>
|
||||
string(1) "3"
|
||||
}
|
||||
array(3) {
|
||||
["green"]=>
|
||||
int(0)
|
||||
["red"]=>
|
||||
int(1)
|
||||
["yellow"]=>
|
||||
int(2)
|
||||
}
|
||||
array(3) {
|
||||
["green"]=>
|
||||
bool(true)
|
||||
["red"]=>
|
||||
bool(false)
|
||||
["yellow"]=>
|
||||
NULL
|
||||
}
|
||||
array(3) {
|
||||
[1]=>
|
||||
string(5) "green"
|
||||
[2]=>
|
||||
string(3) "red"
|
||||
[3]=>
|
||||
string(6) "yellow"
|
||||
}
|
||||
array(3) {
|
||||
[1]=>
|
||||
string(1) "1"
|
||||
[2]=>
|
||||
string(1) "2"
|
||||
[3]=>
|
||||
string(1) "3"
|
||||
}
|
||||
array(3) {
|
||||
[1]=>
|
||||
int(0)
|
||||
[2]=>
|
||||
int(1)
|
||||
[3]=>
|
||||
int(2)
|
||||
}
|
||||
array(3) {
|
||||
[1]=>
|
||||
bool(true)
|
||||
[2]=>
|
||||
bool(false)
|
||||
[3]=>
|
||||
NULL
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(5) "green"
|
||||
[1]=>
|
||||
string(3) "red"
|
||||
[2]=>
|
||||
string(6) "yellow"
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(1) "1"
|
||||
[1]=>
|
||||
string(1) "2"
|
||||
[2]=>
|
||||
string(1) "3"
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(0)
|
||||
[1]=>
|
||||
int(1)
|
||||
[2]=>
|
||||
int(2)
|
||||
}
|
||||
array(3) {
|
||||
[0]=>
|
||||
bool(true)
|
||||
[1]=>
|
||||
bool(false)
|
||||
[2]=>
|
||||
NULL
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(5) "green"
|
||||
[""]=>
|
||||
string(6) "yellow"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
string(1) "1"
|
||||
[""]=>
|
||||
string(1) "3"
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
int(0)
|
||||
[""]=>
|
||||
int(2)
|
||||
}
|
||||
array(2) {
|
||||
[1]=>
|
||||
bool(true)
|
||||
[""]=>
|
||||
NULL
|
||||
}
|
||||
|
79
ext/standard/tests/strings/str_decrement_basic.phpt
Normal file
79
ext/standard/tests/strings/str_decrement_basic.phpt
Normal file
@ -0,0 +1,79 @@
|
||||
--TEST--
|
||||
str_decrement(): Decrementing various strings
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strictlyAlphaNumeric = [
|
||||
"Az",
|
||||
"aZ",
|
||||
"A9",
|
||||
"a9",
|
||||
// Carrying values until the beginning of the string (no underflow)
|
||||
"Za",
|
||||
"zA",
|
||||
"Z0",
|
||||
"z0",
|
||||
// Underflow, removing leading character
|
||||
"Aa",
|
||||
"aA",
|
||||
"A0",
|
||||
"a0",
|
||||
"10",
|
||||
"1A",
|
||||
"1a",
|
||||
"10a",
|
||||
// string interpretable as a number in scientific notation
|
||||
"5e6",
|
||||
// Interned strings
|
||||
"d",
|
||||
"D",
|
||||
"4",
|
||||
];
|
||||
|
||||
foreach ($strictlyAlphaNumeric as $s) {
|
||||
var_dump(str_decrement($s));
|
||||
var_dump($s);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(2) "Ay"
|
||||
string(2) "Az"
|
||||
string(2) "aY"
|
||||
string(2) "aZ"
|
||||
string(2) "A8"
|
||||
string(2) "A9"
|
||||
string(2) "a8"
|
||||
string(2) "a9"
|
||||
string(2) "Yz"
|
||||
string(2) "Za"
|
||||
string(2) "yZ"
|
||||
string(2) "zA"
|
||||
string(2) "Y9"
|
||||
string(2) "Z0"
|
||||
string(2) "y9"
|
||||
string(2) "z0"
|
||||
string(1) "z"
|
||||
string(2) "Aa"
|
||||
string(1) "Z"
|
||||
string(2) "aA"
|
||||
string(1) "9"
|
||||
string(2) "A0"
|
||||
string(1) "9"
|
||||
string(2) "a0"
|
||||
string(1) "9"
|
||||
string(2) "10"
|
||||
string(1) "Z"
|
||||
string(2) "1A"
|
||||
string(1) "z"
|
||||
string(2) "1a"
|
||||
string(2) "9z"
|
||||
string(3) "10a"
|
||||
string(3) "5e5"
|
||||
string(3) "5e6"
|
||||
string(1) "c"
|
||||
string(1) "d"
|
||||
string(1) "C"
|
||||
string(1) "D"
|
||||
string(1) "3"
|
||||
string(1) "4"
|
53
ext/standard/tests/strings/str_decrement_errors.phpt
Normal file
53
ext/standard/tests/strings/str_decrement_errors.phpt
Normal file
@ -0,0 +1,53 @@
|
||||
--TEST--
|
||||
str_decrement(): Invalid strings to decrement should throw a ValueError
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strings = [
|
||||
// Empty string
|
||||
"",
|
||||
// String increments are unaware of being "negative"
|
||||
"-cc",
|
||||
// Trailing whitespace
|
||||
"Z ",
|
||||
// Leading whitespace
|
||||
" Z",
|
||||
// Non-ASCII characters
|
||||
"é",
|
||||
"あいうえお",
|
||||
"α",
|
||||
"ω",
|
||||
"Α", // Capital alpha
|
||||
"Ω",
|
||||
// With period
|
||||
"foo1.txt",
|
||||
"1f.5",
|
||||
// With multiple period
|
||||
"foo.1.txt",
|
||||
"1.f.5",
|
||||
];
|
||||
|
||||
foreach ($strings as $s) {
|
||||
try {
|
||||
var_dump(str_decrement($s));
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
str_decrement(): Argument #1 ($string) cannot be empty
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
32
ext/standard/tests/strings/str_decrement_underflow.phpt
Normal file
32
ext/standard/tests/strings/str_decrement_underflow.phpt
Normal file
@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
str_decrement(): Out of Range ValueErrors for strings that cannot be decremented
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strings = [
|
||||
"",
|
||||
"0",
|
||||
"a",
|
||||
"A",
|
||||
"00",
|
||||
"0a",
|
||||
"0A",
|
||||
];
|
||||
|
||||
foreach ($strings as $s) {
|
||||
try {
|
||||
var_dump(str_decrement($s));
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
str_decrement(): Argument #1 ($string) cannot be empty
|
||||
str_decrement(): Argument #1 ($string) "0" is out of decrement range
|
||||
str_decrement(): Argument #1 ($string) "a" is out of decrement range
|
||||
str_decrement(): Argument #1 ($string) "A" is out of decrement range
|
||||
str_decrement(): Argument #1 ($string) "00" is out of decrement range
|
||||
str_decrement(): Argument #1 ($string) "0a" is out of decrement range
|
||||
str_decrement(): Argument #1 ($string) "0A" is out of decrement range
|
54
ext/standard/tests/strings/str_increment_basic.phpt
Normal file
54
ext/standard/tests/strings/str_increment_basic.phpt
Normal file
@ -0,0 +1,54 @@
|
||||
--TEST--
|
||||
str_increment(): Incrementing various strings
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strictlyAlphaNumeric = [
|
||||
"Az",
|
||||
"aZ",
|
||||
"A9",
|
||||
"a9",
|
||||
// Carrying values until the beginning of the string
|
||||
"Zz",
|
||||
"zZ",
|
||||
"9z",
|
||||
"9Z",
|
||||
// string interpretable as a number in scientific notation
|
||||
"5e6",
|
||||
// Interned strings
|
||||
"d",
|
||||
"D",
|
||||
"4",
|
||||
];
|
||||
|
||||
foreach ($strictlyAlphaNumeric as $s) {
|
||||
var_dump(str_increment($s));
|
||||
var_dump($s);
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(2) "Ba"
|
||||
string(2) "Az"
|
||||
string(2) "bA"
|
||||
string(2) "aZ"
|
||||
string(2) "B0"
|
||||
string(2) "A9"
|
||||
string(2) "b0"
|
||||
string(2) "a9"
|
||||
string(3) "AAa"
|
||||
string(2) "Zz"
|
||||
string(3) "aaA"
|
||||
string(2) "zZ"
|
||||
string(3) "10a"
|
||||
string(2) "9z"
|
||||
string(3) "10A"
|
||||
string(2) "9Z"
|
||||
string(3) "5e7"
|
||||
string(3) "5e6"
|
||||
string(1) "e"
|
||||
string(1) "d"
|
||||
string(1) "E"
|
||||
string(1) "D"
|
||||
string(1) "5"
|
||||
string(1) "4"
|
53
ext/standard/tests/strings/str_increment_errors.phpt
Normal file
53
ext/standard/tests/strings/str_increment_errors.phpt
Normal file
@ -0,0 +1,53 @@
|
||||
--TEST--
|
||||
str_increment(): Invalid strings to increment should throw a ValueError
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$strings = [
|
||||
// Empty string
|
||||
"",
|
||||
// String increments are unaware of being "negative"
|
||||
"-cc",
|
||||
// Trailing whitespace
|
||||
"Z ",
|
||||
// Leading whitespace
|
||||
" Z",
|
||||
// Non-ASCII characters
|
||||
"é",
|
||||
"あいうえお",
|
||||
"α",
|
||||
"ω",
|
||||
"Α", // Capital alpha
|
||||
"Ω",
|
||||
// With period
|
||||
"foo1.txt",
|
||||
"1f.5",
|
||||
// With multiple period
|
||||
"foo.1.txt",
|
||||
"1.f.5",
|
||||
];
|
||||
|
||||
foreach ($strings as $s) {
|
||||
try {
|
||||
var_dump(str_increment($s));
|
||||
} catch (ValueError $e) {
|
||||
echo $e->getMessage(), PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
str_increment(): Argument #1 ($string) cannot be empty
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
||||
str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters
|
59
ext/standard/tests/strings/str_increment_polyfill.phpt
Normal file
59
ext/standard/tests/strings/str_increment_polyfill.phpt
Normal file
@ -0,0 +1,59 @@
|
||||
--TEST--
|
||||
Verifying that the str_increment() polyfill behaves the same
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function polyfill(string $s): string {
|
||||
if (is_numeric($s)) {
|
||||
$offset = stripos($s, 'e');
|
||||
if ($offset !== false) {
|
||||
/* Using increment operator would cast the string to float
|
||||
* Therefore we manually increment it to convert it to an "f"/"F" that doesn't get affected */
|
||||
$c = $s[$offset];
|
||||
$c++;
|
||||
$s[$offset] = $c;
|
||||
$s++;
|
||||
$s[$offset] = match ($s[$offset]) {
|
||||
'f' => 'e',
|
||||
'F' => 'E',
|
||||
'g' => 'f',
|
||||
'G' => 'F',
|
||||
};
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
return ++$s;
|
||||
}
|
||||
|
||||
$strictlyAlphaNumeric = [
|
||||
"Az",
|
||||
"aZ",
|
||||
"A9",
|
||||
"a9",
|
||||
// Carrying values until the beginning of the string
|
||||
"Zz",
|
||||
"zZ",
|
||||
"9z",
|
||||
"9Z",
|
||||
// string interpretable as a number in scientific notation
|
||||
"5e6",
|
||||
"5E6",
|
||||
"5e9",
|
||||
"5E9",
|
||||
// Interned strings
|
||||
"d",
|
||||
"D",
|
||||
"4",
|
||||
];
|
||||
|
||||
foreach ($strictlyAlphaNumeric as $s) {
|
||||
if (str_increment($s) !== polyfill($s)) {
|
||||
var_dump("Error:", str_increment($s), polyfill($s));
|
||||
}
|
||||
}
|
||||
|
||||
echo "DONE";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
DONE
|
@ -939,6 +939,116 @@ PHP_METHOD(DoOperationNoCast, __construct)
|
||||
ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l);
|
||||
}
|
||||
|
||||
static zend_class_entry *long_castable_no_operation_ce;
|
||||
static zend_object_handlers long_castable_no_operation_object_handlers;
|
||||
|
||||
static zend_object* long_castable_no_operation_object_create_ex(zend_class_entry* ce, zend_long l) {
|
||||
zend_object *obj = zend_objects_new(ce);
|
||||
object_properties_init(obj, ce);
|
||||
obj->handlers = &long_castable_no_operation_object_handlers;
|
||||
ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static zend_object *long_castable_no_operation_object_create(zend_class_entry *ce)
|
||||
{
|
||||
return long_castable_no_operation_object_create_ex(ce, 0);
|
||||
}
|
||||
|
||||
static zend_result long_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
|
||||
{
|
||||
if (type == IS_LONG) {
|
||||
ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHP_METHOD(LongCastableNoOperations, __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);
|
||||
}
|
||||
|
||||
static zend_class_entry *float_castable_no_operation_ce;
|
||||
static zend_object_handlers float_castable_no_operation_object_handlers;
|
||||
|
||||
static zend_object* float_castable_no_operation_object_create_ex(zend_class_entry* ce, double d) {
|
||||
zend_object *obj = zend_objects_new(ce);
|
||||
object_properties_init(obj, ce);
|
||||
obj->handlers = &float_castable_no_operation_object_handlers;
|
||||
ZVAL_DOUBLE(OBJ_PROP_NUM(obj, 0), d);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static zend_object *float_castable_no_operation_object_create(zend_class_entry *ce)
|
||||
{
|
||||
return float_castable_no_operation_object_create_ex(ce, 0.0);
|
||||
}
|
||||
|
||||
static zend_result float_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
|
||||
{
|
||||
if (type == IS_DOUBLE) {
|
||||
ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHP_METHOD(FloatCastableNoOperations, __construct)
|
||||
{
|
||||
double d;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_DOUBLE(d)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
ZVAL_DOUBLE(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), d);
|
||||
}
|
||||
|
||||
static zend_class_entry *numeric_castable_no_operation_ce;
|
||||
static zend_object_handlers numeric_castable_no_operation_object_handlers;
|
||||
|
||||
static zend_object* numeric_castable_no_operation_object_create_ex(zend_class_entry* ce, const zval *n) {
|
||||
zend_object *obj = zend_objects_new(ce);
|
||||
object_properties_init(obj, ce);
|
||||
obj->handlers = &numeric_castable_no_operation_object_handlers;
|
||||
ZVAL_COPY(OBJ_PROP_NUM(obj, 0), n);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static zend_object *numeric_castable_no_operation_object_create(zend_class_entry *ce)
|
||||
{
|
||||
zval tmp;
|
||||
ZVAL_LONG(&tmp, 0);
|
||||
return numeric_castable_no_operation_object_create_ex(ce, &tmp);
|
||||
}
|
||||
|
||||
static zend_result numeric_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
|
||||
{
|
||||
if (type == _IS_NUMBER) {
|
||||
ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHP_METHOD(NumericCastableNoOperations, __construct)
|
||||
{
|
||||
zval *n;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_NUMBER(n)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
ZVAL_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), n);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1011,6 +1121,22 @@ PHP_MINIT_FUNCTION(zend_test)
|
||||
memcpy(&donc_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
donc_object_handlers.do_operation = donc_do_operation;
|
||||
|
||||
/* CastableNoOperation classes */
|
||||
long_castable_no_operation_ce = register_class_LongCastableNoOperations();
|
||||
long_castable_no_operation_ce->create_object = long_castable_no_operation_object_create;
|
||||
memcpy(&long_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
long_castable_no_operation_object_handlers.cast_object = long_castable_no_operation_cast_object;
|
||||
|
||||
float_castable_no_operation_ce = register_class_FloatCastableNoOperations();
|
||||
float_castable_no_operation_ce->create_object = float_castable_no_operation_object_create;
|
||||
memcpy(&float_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
float_castable_no_operation_object_handlers.cast_object = float_castable_no_operation_cast_object;
|
||||
|
||||
numeric_castable_no_operation_ce = register_class_NumericCastableNoOperations();
|
||||
numeric_castable_no_operation_ce->create_object = numeric_castable_no_operation_object_create;
|
||||
memcpy(&numeric_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
|
||||
numeric_castable_no_operation_object_handlers.cast_object = numeric_castable_no_operation_cast_object;
|
||||
|
||||
zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type);
|
||||
|
||||
// Loading via dl() not supported with the observer API
|
||||
|
@ -132,6 +132,19 @@ namespace {
|
||||
public function __construct(int $val) {}
|
||||
}
|
||||
|
||||
final class LongCastableNoOperations {
|
||||
private int $val;
|
||||
public function __construct(int $val) {}
|
||||
}
|
||||
final class FloatCastableNoOperations {
|
||||
private float $val;
|
||||
public function __construct(float $val) {}
|
||||
}
|
||||
final class NumericCastableNoOperations {
|
||||
private int|float $val;
|
||||
public function __construct(int|float $val) {}
|
||||
}
|
||||
|
||||
function zend_test_array_return(): array {}
|
||||
|
||||
function zend_test_nullable_array_return(): null|array {}
|
||||
|
84
ext/zend_test/test_arginfo.h
generated
84
ext/zend_test/test_arginfo.h
generated
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 46e6d8be5504acb6ecbb722da4fabfcea4e8a354 */
|
||||
* Stub hash: 3c1b17bbb7ef84e036a251c685bd7fd79fe9f434 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@ -189,6 +189,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DoOperationNoCast___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, val, IS_LONG, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_LongCastableNoOperations___construct arginfo_class_DoOperationNoCast___construct
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_FloatCastableNoOperations___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, val, IS_DOUBLE, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NumericCastableNoOperations___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_MASK(0, val, MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
|
||||
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
|
||||
@ -260,6 +270,9 @@ static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override)
|
||||
static ZEND_METHOD(ZendTestForbidDynamicCall, call);
|
||||
static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic);
|
||||
static ZEND_METHOD(DoOperationNoCast, __construct);
|
||||
static ZEND_METHOD(LongCastableNoOperations, __construct);
|
||||
static ZEND_METHOD(FloatCastableNoOperations, __construct);
|
||||
static ZEND_METHOD(NumericCastableNoOperations, __construct);
|
||||
static ZEND_METHOD(ZendTestNS_Foo, method);
|
||||
static ZEND_METHOD(ZendTestNS_UnlikelyCompileError, method);
|
||||
static ZEND_METHOD(ZendTestNS2_Foo, method);
|
||||
@ -403,6 +416,24 @@ static const zend_function_entry class_DoOperationNoCast_methods[] = {
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_LongCastableNoOperations_methods[] = {
|
||||
ZEND_ME(LongCastableNoOperations, __construct, arginfo_class_LongCastableNoOperations___construct, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_FloatCastableNoOperations_methods[] = {
|
||||
ZEND_ME(FloatCastableNoOperations, __construct, arginfo_class_FloatCastableNoOperations___construct, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
|
||||
static const zend_function_entry class_NumericCastableNoOperations_methods[] = {
|
||||
ZEND_ME(NumericCastableNoOperations, __construct, arginfo_class_NumericCastableNoOperations___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
|
||||
@ -792,6 +823,57 @@ static zend_class_entry *register_class_DoOperationNoCast(void)
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_LongCastableNoOperations(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "LongCastableNoOperations", class_LongCastableNoOperations_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_FloatCastableNoOperations(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "FloatCastableNoOperations", class_FloatCastableNoOperations_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_DOUBLE));
|
||||
zend_string_release(property_val_name);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_NumericCastableNoOperations(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_CLASS_ENTRY(ce, "NumericCastableNoOperations", class_NumericCastableNoOperations_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|MAY_BE_DOUBLE));
|
||||
zend_string_release(property_val_name);
|
||||
|
||||
return class_entry;
|
||||
}
|
||||
|
||||
static zend_class_entry *register_class_ZendTestNS_Foo(void)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
@ -16,7 +16,7 @@ foreach ($strVals as $strVal) {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
--- testing: '0' ---
|
||||
int(-1)
|
||||
--- testing: '65' ---
|
||||
@ -28,20 +28,36 @@ float(0.19999999999999996)
|
||||
--- testing: '-7.7' ---
|
||||
float(-8.7)
|
||||
--- testing: 'abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(3) "abc"
|
||||
--- testing: '123abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(6) "123abc"
|
||||
--- testing: '123e5' ---
|
||||
float(12299999)
|
||||
--- testing: '123e5xyz' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(8) "123e5xyz"
|
||||
--- testing: ' 123abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) " 123abc"
|
||||
--- testing: '123 abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) "123 abc"
|
||||
--- testing: '123abc ' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) "123abc "
|
||||
--- testing: '3.4a' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(4) "3.4a"
|
||||
--- testing: 'a5.9' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(4) "a5.9"
|
||||
|
@ -16,7 +16,7 @@ foreach ($strVals as $strVal) {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
--- testing: '0' ---
|
||||
int(1)
|
||||
--- testing: '65' ---
|
||||
@ -36,12 +36,22 @@ float(12300001)
|
||||
--- testing: '123e5xyz' ---
|
||||
string(8) "123e5xza"
|
||||
--- testing: ' 123abc' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) " 123abd"
|
||||
--- testing: '123 abc' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) "123 abd"
|
||||
--- testing: '123abc ' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) "123abc "
|
||||
--- testing: '3.4a' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(4) "3.4b"
|
||||
--- testing: 'a5.9' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(4) "a5.0"
|
||||
|
@ -15,7 +15,7 @@ foreach ($strVals as $strVal) {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
--- testing: '0' ---
|
||||
int(-1)
|
||||
--- testing: '65' ---
|
||||
@ -27,20 +27,36 @@ float(0.19999999999999996)
|
||||
--- testing: '-7.7' ---
|
||||
float(-8.7)
|
||||
--- testing: 'abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(3) "abc"
|
||||
--- testing: '123abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(6) "123abc"
|
||||
--- testing: '123e5' ---
|
||||
float(12299999)
|
||||
--- testing: '123e5xyz' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(8) "123e5xyz"
|
||||
--- testing: ' 123abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) " 123abc"
|
||||
--- testing: '123 abc' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) "123 abc"
|
||||
--- testing: '123abc ' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(7) "123abc "
|
||||
--- testing: '3.4a' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(4) "3.4a"
|
||||
--- testing: 'a5.9' ---
|
||||
|
||||
Deprecated: Decrement on non-numeric string has no effect and is deprecated %s on line %d
|
||||
string(4) "a5.9"
|
||||
|
@ -16,7 +16,7 @@ foreach ($strVals as $strVal) {
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
--EXPECTF--
|
||||
--- testing: '0' ---
|
||||
int(1)
|
||||
--- testing: '65' ---
|
||||
@ -36,14 +36,24 @@ float(12300001)
|
||||
--- testing: '123e5xyz' ---
|
||||
string(8) "123e5xza"
|
||||
--- testing: ' 123abc' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) " 123abd"
|
||||
--- testing: '123 abc' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) "123 abd"
|
||||
--- testing: '123abc ' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(7) "123abc "
|
||||
--- testing: '3.4a' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(4) "3.4b"
|
||||
--- testing: 'a5.9' ---
|
||||
|
||||
Deprecated: Increment on non-alphanumeric string is deprecated in %s on line %d
|
||||
string(4) "a5.0"
|
||||
--- testing: 'z' ---
|
||||
string(2) "aa"
|
||||
|
Loading…
Reference in New Issue
Block a user