[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:
George Peter Banyard 2023-07-17 15:51:24 +01:00 committed by GitHub
parent 2f318cfb06
commit d8696f9216
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1897 additions and 361 deletions

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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)

View 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

View 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) "🐘"

View 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) "🐘"

View 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)

View File

@ -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)

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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)

View 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)

View File

@ -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

View File

@ -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--

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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
View File

@ -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();

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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');

View File

@ -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());

View File

@ -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());

View File

@ -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 {}

View File

@ -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)

View File

@ -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)
{

View File

@ -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
}

View 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"

View 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

View 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

View 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"

View 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

View 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

View File

@ -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

View File

@ -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 {}

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"