mirror of
https://github.com/php/php-src.git
synced 2024-11-27 03:44:07 +08:00
Implement typed properties
RFC: https://wiki.php.net/rfc/typed_properties_v2 This is a squash of PR #3734, which is a squash of PR #3313. Co-authored-by: Bob Weinand <bobwei9@hotmail.com> Co-authored-by: Joe Watkins <krakjoe@php.net> Co-authored-by: Dmitry Stogov <dmitry@zend.com>
This commit is contained in:
parent
fe8fdfa3bd
commit
e219ec144e
14
UPGRADING
14
UPGRADING
@ -78,8 +78,20 @@ PHP 7.4 UPGRADE NOTES
|
||||
2. New Features
|
||||
========================================
|
||||
|
||||
- Core:
|
||||
. Added support for typed properties. For example:
|
||||
|
||||
class User {
|
||||
public int $id;
|
||||
public string $name;
|
||||
}
|
||||
|
||||
This will enforce that $user->id can only be assigned integer and
|
||||
$user->name can only be assigned strings. For more information see the
|
||||
RFC: https://wiki.php.net/rfc/typed_properties_v2
|
||||
|
||||
- PDO_OCI:
|
||||
. PDOStatement::getColumnMeta is now available
|
||||
. PDOStatement::getColumnMeta() is now available
|
||||
|
||||
- PDO_SQLite:
|
||||
. PDOStatement::getAttribute(PDO::SQLITE_ATTR_READONLY_STATEMENT) allows to
|
||||
|
@ -13,6 +13,8 @@ PHP 7.4 INTERNALS UPGRADE NOTES
|
||||
j. Removed add_get_assoc_*() and add_get_index_*()
|
||||
k. Class declaration opcodes
|
||||
l. HASH_FLAG_INITIALIZED
|
||||
m. write_property return value
|
||||
n. Assignments to references
|
||||
|
||||
2. Build system changes
|
||||
a. Abstract
|
||||
@ -158,6 +160,17 @@ PHP 7.4 INTERNALS UPGRADE NOTES
|
||||
Special HT_IS_INITIALIZED() and HT_INVALIDATE() macro were introduced
|
||||
to hide implementation details.
|
||||
|
||||
m. The write_property() object handler now returns the assigned value (after
|
||||
possible type coercions) rather than void. For extensions, it should
|
||||
usually be sufficient to return whatever was passed as the argument.
|
||||
|
||||
n. Assignments to references now need to ensure that they respect property
|
||||
types that affect the reference. This means that references should no
|
||||
longer be directly assigned to, and instead a set of specialized macros
|
||||
of the form ZEND_TRY_ASSIGN* needs to be used. You can find detailed
|
||||
porting instructions as well as a compatibility shim in the wiki:
|
||||
https://wiki.php.net/rfc/typed_properties_v2#assignments_to_references
|
||||
|
||||
========================
|
||||
2. Build system changes
|
||||
========================
|
||||
|
44
Zend/tests/type_declarations/typed_properties_001.phpt
Normal file
44
Zend/tests/type_declarations/typed_properties_001.phpt
Normal file
@ -0,0 +1,44 @@
|
||||
--TEST--
|
||||
Test typed properties basic operation
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(new class(1, 2.2, true, ["four"], new stdClass) {
|
||||
public int $int;
|
||||
public float $float;
|
||||
public bool $bool;
|
||||
public array $array;
|
||||
public stdClass $std;
|
||||
public iterable $it;
|
||||
|
||||
public function __construct(int $int, float $float, bool $bool, array $array, stdClass $std) {
|
||||
$this->int = $int;
|
||||
$this->float = $float;
|
||||
$this->bool = $bool;
|
||||
$this->array = $array;
|
||||
$this->std = $std;
|
||||
$this->it = $array;
|
||||
}
|
||||
});
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(class@anonymous)#%d (6) {
|
||||
["int"]=>
|
||||
int(1)
|
||||
["float"]=>
|
||||
float(2.2)
|
||||
["bool"]=>
|
||||
bool(true)
|
||||
["array"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(4) "four"
|
||||
}
|
||||
["std"]=>
|
||||
object(stdClass)#%d (0) {
|
||||
}
|
||||
["it"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(4) "four"
|
||||
}
|
||||
}
|
15
Zend/tests/type_declarations/typed_properties_002.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_002.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties error condition (read uninitialized)
|
||||
--FILE--
|
||||
<?php
|
||||
$thing = new class() {
|
||||
public int $int;
|
||||
};
|
||||
|
||||
var_dump($thing->int);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Typed property class@anonymous::$int must not be accessed before initialization in %s:6
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line 6
|
15
Zend/tests/type_declarations/typed_properties_003.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_003.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties error condition (fetch uninitialized by reference)
|
||||
--FILE--
|
||||
<?php
|
||||
$thing = new class() {
|
||||
public int $int;
|
||||
};
|
||||
|
||||
$var = &$thing->int;
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Cannot access uninitialized non-nullable property class@anonymous::$int by reference in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
18
Zend/tests/type_declarations/typed_properties_004.phpt
Normal file
18
Zend/tests/type_declarations/typed_properties_004.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Test typed properties error condition (type mismatch)
|
||||
--FILE--
|
||||
<?php
|
||||
new class("PHP 7 is better than you, and it knows it ...") {
|
||||
public int $int;
|
||||
|
||||
public function __construct(string $string) {
|
||||
$this->int = $string;
|
||||
}
|
||||
};
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: Typed property class@anonymous::$int must be int, string used in %s:6
|
||||
Stack trace:
|
||||
#0 %s(2): class@anonymous->__construct('PHP 7 is better...')
|
||||
#1 {main}
|
||||
thrown in %s on line 6
|
20
Zend/tests/type_declarations/typed_properties_005.phpt
Normal file
20
Zend/tests/type_declarations/typed_properties_005.phpt
Normal file
@ -0,0 +1,20 @@
|
||||
--TEST--
|
||||
Test typed properties error condition (type mismatch object)
|
||||
--FILE--
|
||||
<?php
|
||||
class Dummy {}
|
||||
|
||||
new class(new Dummy) {
|
||||
public stdClass $std;
|
||||
|
||||
public function __construct(Dummy $dummy) {
|
||||
$this->std = $dummy;
|
||||
}
|
||||
};
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: Typed property class@anonymous::$std must be an instance of stdClass, Dummy used in %s:8
|
||||
Stack trace:
|
||||
#0 %s(4): class@anonymous->__construct(Object(Dummy))
|
||||
#1 {main}
|
||||
thrown in %s on line 8
|
14
Zend/tests/type_declarations/typed_properties_006.phpt
Normal file
14
Zend/tests/type_declarations/typed_properties_006.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
Test typed properties inheritance (scalar)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $qux;
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
public string $qux;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Type of Bar::$qux must be int (as in class Foo) in %s on line 8
|
17
Zend/tests/type_declarations/typed_properties_007.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_007.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Test typed properties inheritance
|
||||
--FILE--
|
||||
<?php
|
||||
class Whatever {}
|
||||
class Thing extends Whatever {}
|
||||
|
||||
class Foo {
|
||||
public Whatever $qux;
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
public Thing $qux;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Type of Bar::$qux must be Whatever (as in class Foo) in %s on line 11
|
14
Zend/tests/type_declarations/typed_properties_008.phpt
Normal file
14
Zend/tests/type_declarations/typed_properties_008.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
Test typed properties inheritance (missing info)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $qux;
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
public $qux;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Type of Bar::$qux must be int (as in class Foo) in %s on line 8
|
23
Zend/tests/type_declarations/typed_properties_009.phpt
Normal file
23
Zend/tests/type_declarations/typed_properties_009.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Test typed properties unset leaves properties in an uninitialized state
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar;
|
||||
|
||||
public function __get($name) {
|
||||
var_dump($name);
|
||||
/* return value has to be compatible with int */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
unset($foo->bar);
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "bar"
|
||||
int(0)
|
17
Zend/tests/type_declarations/typed_properties_010.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_010.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Test typed properties allow fetch reference
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = 1;
|
||||
}
|
||||
|
||||
$cb = function(int &$bar) {
|
||||
var_dump($bar);
|
||||
};
|
||||
|
||||
$foo = new Foo();
|
||||
$cb($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
18
Zend/tests/type_declarations/typed_properties_011.phpt
Normal file
18
Zend/tests/type_declarations/typed_properties_011.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Test typed properties allow fetch reference for init array
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = 1;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
$array = [&$foo->bar];
|
||||
var_dump($array);
|
||||
?>
|
||||
--EXPECT--
|
||||
array(1) {
|
||||
[0]=>
|
||||
&int(1)
|
||||
}
|
19
Zend/tests/type_declarations/typed_properties_012.phpt
Normal file
19
Zend/tests/type_declarations/typed_properties_012.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Test typed properties allow fetch reference for foreach
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = 1;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
foreach ($foo as &$prop) {
|
||||
$prop++;
|
||||
}
|
||||
var_dump($foo);
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Foo)#1 (1) {
|
||||
["bar"]=>
|
||||
&int(2)
|
||||
}
|
10
Zend/tests/type_declarations/typed_properties_013.phpt
Normal file
10
Zend/tests/type_declarations/typed_properties_013.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
Test typed properties disallow incorrect type initial value (scalar)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = "string";
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Default value for property of type int can only be int in %s on line 3
|
10
Zend/tests/type_declarations/typed_properties_014.phpt
Normal file
10
Zend/tests/type_declarations/typed_properties_014.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
Test typed properties disallow incorrect type initial value (array)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public array $bar = 32;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Default value for property of type array can only be an array in %s on line 3
|
10
Zend/tests/type_declarations/typed_properties_015.phpt
Normal file
10
Zend/tests/type_declarations/typed_properties_015.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
Test typed properties disallow incorrect type initial value (object)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public stdClass $bar = null;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Default value for property of type stdClass may not be null. Use the nullable type ?stdClass to allow null default value in %s on line %d
|
16
Zend/tests/type_declarations/typed_properties_016.phpt
Normal file
16
Zend/tests/type_declarations/typed_properties_016.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Test typed properties initial values
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $int = 1;
|
||||
public float $flt = 2.2;
|
||||
public float $flt2 = 2;
|
||||
public array $arr = [];
|
||||
public bool $bool = false;
|
||||
public iterable $iter = [];
|
||||
}
|
||||
echo "ok\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
ok
|
12
Zend/tests/type_declarations/typed_properties_017.phpt
Normal file
12
Zend/tests/type_declarations/typed_properties_017.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
Test typed properties disallow void
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public void $int;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Property Foo::$int cannot have type void in %s on line 3
|
17
Zend/tests/type_declarations/typed_properties_018.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_018.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Test typed properties type applies to all props in group
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar,
|
||||
$qux;
|
||||
}
|
||||
|
||||
$reflector = new ReflectionClass(Foo::class);
|
||||
|
||||
$prop = $reflector->getProperty("qux");
|
||||
|
||||
var_dump((string) $prop->getType());
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "int"
|
22
Zend/tests/type_declarations/typed_properties_019.phpt
Normal file
22
Zend/tests/type_declarations/typed_properties_019.phpt
Normal file
@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
Test typed properties int must not be allowed to overflow
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = PHP_INT_MAX;
|
||||
|
||||
public function inc() {
|
||||
return ++$this->bar;
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
try {
|
||||
$foo->inc();
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot increment property Foo::$bar of type int past its maximal value
|
26
Zend/tests/type_declarations/typed_properties_020.phpt
Normal file
26
Zend/tests/type_declarations/typed_properties_020.phpt
Normal file
@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
Test typed properties binary assign op helper test
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class Foo {
|
||||
public int $bar = 0;
|
||||
|
||||
public function __construct() {
|
||||
$this->bar += 2;
|
||||
try {
|
||||
$this->bar += 1.5;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property Foo::$bar must be int, float used
|
||||
int(2)
|
15
Zend/tests/type_declarations/typed_properties_021.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_021.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties delay type check on constant
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = BAR::BAZ;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Class 'BAR' not found in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
15
Zend/tests/type_declarations/typed_properties_022.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_022.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties delay type check on ast
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = BAR::BAZ * 2;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Class 'BAR' not found in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
52
Zend/tests/type_declarations/typed_properties_023.phpt
Normal file
52
Zend/tests/type_declarations/typed_properties_023.phpt
Normal file
@ -0,0 +1,52 @@
|
||||
--TEST--
|
||||
Test typed static property
|
||||
--FILE--
|
||||
<?php
|
||||
function &ref() {
|
||||
static $a = 5;
|
||||
return $a;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public static int $i;
|
||||
public static string $s = "x";
|
||||
}
|
||||
|
||||
var_dump(Foo::$i = 1);
|
||||
var_dump(Foo::$i);
|
||||
var_dump(Foo::$i = "1");
|
||||
var_dump(Foo::$i);
|
||||
|
||||
var_dump(Foo::$s);
|
||||
var_dump(Foo::$s = Foo::$i++);
|
||||
var_dump(Foo::$s, Foo::$i);
|
||||
$a = 3;
|
||||
var_dump(Foo::$s = $a);
|
||||
var_dump(Foo::$s);
|
||||
var_dump(Foo::$i = "4");
|
||||
var_dump(Foo::$i);
|
||||
|
||||
var_dump(Foo::$i = ref());
|
||||
var_dump(Foo::$i);
|
||||
var_dump(Foo::$s = ref());
|
||||
var_dump(Foo::$s);
|
||||
var_dump(ref());
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
||||
int(1)
|
||||
int(1)
|
||||
int(1)
|
||||
string(1) "x"
|
||||
string(1) "1"
|
||||
string(1) "1"
|
||||
int(2)
|
||||
string(1) "3"
|
||||
string(1) "3"
|
||||
int(4)
|
||||
int(4)
|
||||
int(5)
|
||||
int(5)
|
||||
string(1) "5"
|
||||
string(1) "5"
|
||||
int(5)
|
16
Zend/tests/type_declarations/typed_properties_024.phpt
Normal file
16
Zend/tests/type_declarations/typed_properties_024.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Test typed properties ignore private props during inheritance
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
private int $thing;
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
public string $thing; // No conflict
|
||||
}
|
||||
|
||||
echo "ok";
|
||||
?>
|
||||
--EXPECT--
|
||||
ok
|
11
Zend/tests/type_declarations/typed_properties_025.phpt
Normal file
11
Zend/tests/type_declarations/typed_properties_025.phpt
Normal file
@ -0,0 +1,11 @@
|
||||
--TEST--
|
||||
Test typed properties type must preceed first declaration in group
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public $bar,
|
||||
int $qux;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Parse error: syntax error, unexpected 'int' (T_STRING), expecting variable (T_VARIABLE) in %s on line 4
|
23
Zend/tests/type_declarations/typed_properties_026.phpt
Normal file
23
Zend/tests/type_declarations/typed_properties_026.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Test typed properties inherit traits with typed properties
|
||||
--FILE--
|
||||
<?php
|
||||
trait Foo{
|
||||
private int $baz;
|
||||
}
|
||||
|
||||
class Baz{
|
||||
use Foo;
|
||||
|
||||
function get(){
|
||||
return $this->baz;
|
||||
}
|
||||
}
|
||||
|
||||
var_dump((new Baz)->get());
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught Error: Typed property Baz::$baz must not be accessed before initialization in %s:10
|
||||
Stack trace:
|
||||
#0 %s(14): Baz->get()
|
||||
#1 {main}
|
||||
thrown in %s on line 10
|
16
Zend/tests/type_declarations/typed_properties_027.phpt
Normal file
16
Zend/tests/type_declarations/typed_properties_027.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Test typed properties float widen at runtime
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public float $bar = 1.1;
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
$foo->bar = 10;
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
float(10)
|
15
Zend/tests/type_declarations/typed_properties_028.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_028.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties respect strict types (off)
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar;
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
$foo->bar = "1";
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(1)
|
18
Zend/tests/type_declarations/typed_properties_029.phpt
Normal file
18
Zend/tests/type_declarations/typed_properties_029.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Test typed properties respect strict types (on)
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class Foo {
|
||||
public int $bar;
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
$foo->bar = "1";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: Typed property Foo::$bar must be int, string used in %s:9
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line 9
|
25
Zend/tests/type_declarations/typed_properties_030.phpt
Normal file
25
Zend/tests/type_declarations/typed_properties_030.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Test typed properties unset __get magical magic
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar;
|
||||
|
||||
public function __get($name) {
|
||||
return "violate";
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
|
||||
$foo->bar = "1"; # ok
|
||||
|
||||
unset($foo->bar); # ok
|
||||
|
||||
var_dump($foo->bar); # not okay, __get is nasty
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: Typed property Foo::$bar must be int, string used in %s:16
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line 16
|
22
Zend/tests/type_declarations/typed_properties_031.phpt
Normal file
22
Zend/tests/type_declarations/typed_properties_031.phpt
Normal file
@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
Test typed properties coerce int to float even in strict mode
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class Bar
|
||||
{
|
||||
public float $bar;
|
||||
|
||||
public function setBar($value) {
|
||||
$this->bar = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$bar = new Bar();
|
||||
|
||||
$bar->setBar(100);
|
||||
|
||||
var_dump($bar->bar);
|
||||
--EXPECT--
|
||||
float(100)
|
15
Zend/tests/type_declarations/typed_properties_032.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_032.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test typed properties return by ref is allowed
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public int $bar = 15;
|
||||
|
||||
public function &method() {
|
||||
return $this->bar;
|
||||
}
|
||||
};
|
||||
|
||||
var_dump($foo->method());
|
||||
--EXPECT--
|
||||
int(15)
|
38
Zend/tests/type_declarations/typed_properties_033.phpt
Normal file
38
Zend/tests/type_declarations/typed_properties_033.phpt
Normal file
@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
Test typed properties yield reference guard
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public int $foo = 1;
|
||||
public int $bar = 3;
|
||||
public int $baz = 5;
|
||||
public int $qux = PHP_INT_MAX;
|
||||
|
||||
public function &fetch() {
|
||||
yield $this->foo;
|
||||
yield $this->bar;
|
||||
yield $this->baz;
|
||||
yield $this->qux;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
foreach ($foo->fetch() as &$prop) {
|
||||
$prop += 1;
|
||||
}
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
|
||||
var_dump($foo);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Cannot assign float to reference held by property class@anonymous::$qux of type int
|
||||
object(class@anonymous)#1 (4) {
|
||||
["foo"]=>
|
||||
int(2)
|
||||
["bar"]=>
|
||||
int(4)
|
||||
["baz"]=>
|
||||
int(6)
|
||||
["qux"]=>
|
||||
&int(%d)
|
||||
}
|
51
Zend/tests/type_declarations/typed_properties_034.phpt
Normal file
51
Zend/tests/type_declarations/typed_properties_034.phpt
Normal file
@ -0,0 +1,51 @@
|
||||
--TEST--
|
||||
Test typed properties passed to typed function
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public ?int $bar = 42;
|
||||
public int $baz;
|
||||
|
||||
public function &getIterator() {
|
||||
foreach (['1', &$this->bar] as &$item) {
|
||||
yield $item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function foo(?int &$a) {
|
||||
var_dump($a);
|
||||
$a = null;
|
||||
}
|
||||
|
||||
foo($foo->bar);
|
||||
|
||||
try {
|
||||
$foo->baz = &$foo->bar;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
$foo->bar = 10;
|
||||
|
||||
foreach ($foo->getIterator() as &$item) {
|
||||
$foo->baz = &$item;
|
||||
var_dump($foo->baz);
|
||||
}
|
||||
|
||||
try {
|
||||
foo($foo->bar);
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
|
||||
var_dump($foo);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(42)
|
||||
Typed property class@anonymous::$baz must be int, null used
|
||||
int(1)
|
||||
int(10)
|
||||
int(10)
|
||||
Cannot assign null to reference held by property class@anonymous::$baz of type int
|
||||
object(class@anonymous)#1 (2) {
|
||||
["bar"]=>
|
||||
&int(10)
|
||||
["baz"]=>
|
||||
&int(10)
|
||||
}
|
13
Zend/tests/type_declarations/typed_properties_035.phpt
Normal file
13
Zend/tests/type_declarations/typed_properties_035.phpt
Normal file
@ -0,0 +1,13 @@
|
||||
--TEST--
|
||||
Test typed properties inheritance must not change type
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo{
|
||||
public $bar = 42;
|
||||
}
|
||||
|
||||
class Baz extends Foo{
|
||||
public int $bar = 33;
|
||||
}
|
||||
--EXPECTF--
|
||||
Fatal error: Type of Baz::$bar must not be defined (as in class Foo) in %s on line 8
|
15
Zend/tests/type_declarations/typed_properties_036.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_036.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Test unitialized typed properties normal foreach must not be yielded
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public int $bar = 10, $qux;
|
||||
};
|
||||
|
||||
foreach ($foo as $key => $bar) {
|
||||
var_dump($key, $bar);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "bar"
|
||||
int(10)
|
16
Zend/tests/type_declarations/typed_properties_037.phpt
Normal file
16
Zend/tests/type_declarations/typed_properties_037.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Test typed properties var_dump uninitialized
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public int $bar = 10, $qux;
|
||||
};
|
||||
|
||||
var_dump($foo);
|
||||
--EXPECTF--
|
||||
object(class@anonymous)#%d (1) {
|
||||
["bar"]=>
|
||||
int(10)
|
||||
["qux"]=>
|
||||
uninitialized(int)
|
||||
}
|
61
Zend/tests/type_declarations/typed_properties_038.phpt
Normal file
61
Zend/tests/type_declarations/typed_properties_038.phpt
Normal file
@ -0,0 +1,61 @@
|
||||
--TEST--
|
||||
Test typed properties overflowing
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$foo = new class {
|
||||
public int $bar = PHP_INT_MAX;
|
||||
};
|
||||
|
||||
try {
|
||||
$foo->bar++;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump($foo);
|
||||
|
||||
try {
|
||||
$foo->bar += 1;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump($foo);
|
||||
|
||||
try {
|
||||
++$foo->bar;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump($foo);
|
||||
|
||||
try {
|
||||
$foo->bar = $foo->bar + 1;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump($foo);
|
||||
--EXPECTF--
|
||||
string(82) "Cannot increment property class@anonymous::$bar of type int past its maximal value"
|
||||
object(class@anonymous)#1 (1) {
|
||||
["bar"]=>
|
||||
int(%d)
|
||||
}
|
||||
string(60) "Typed property class@anonymous::$bar must be int, float used"
|
||||
object(class@anonymous)#1 (1) {
|
||||
["bar"]=>
|
||||
int(%d)
|
||||
}
|
||||
string(82) "Cannot increment property class@anonymous::$bar of type int past its maximal value"
|
||||
object(class@anonymous)#1 (1) {
|
||||
["bar"]=>
|
||||
int(%d)
|
||||
}
|
||||
string(60) "Typed property class@anonymous::$bar must be int, float used"
|
||||
object(class@anonymous)#1 (1) {
|
||||
["bar"]=>
|
||||
int(%d)
|
||||
}
|
31
Zend/tests/type_declarations/typed_properties_039.phpt
Normal file
31
Zend/tests/type_declarations/typed_properties_039.phpt
Normal file
@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Repeated assign of a variable to mismatched property type must not succeed
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public int $foo;
|
||||
}
|
||||
|
||||
class B {
|
||||
public A $foo;
|
||||
}
|
||||
|
||||
$objs = [new A, new A];
|
||||
$v = 1;
|
||||
|
||||
foreach ($objs as $obj) {
|
||||
$obj->foo = $v;
|
||||
$v = new A;
|
||||
$obj = new B;
|
||||
$obj->foo = $v;
|
||||
}
|
||||
|
||||
var_dump($objs);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught TypeError: Typed property A::$foo must be int, A used in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
25
Zend/tests/type_declarations/typed_properties_040.phpt
Normal file
25
Zend/tests/type_declarations/typed_properties_040.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Test __get on unset typed property must fail properly
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class Foo {
|
||||
public int $bar;
|
||||
|
||||
public function __get($name) {
|
||||
var_dump($name);
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(3) "bar"
|
||||
|
||||
Fatal error: Uncaught TypeError: Typed property Foo::$bar must be int, null used in %s:14
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line 14
|
16
Zend/tests/type_declarations/typed_properties_041.phpt
Normal file
16
Zend/tests/type_declarations/typed_properties_041.phpt
Normal file
@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
Test typed properties weak conversion of strings
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public int $bar = 1;
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
$foo->bar = "10";
|
||||
|
||||
var_dump($foo->bar);
|
||||
?>
|
||||
--EXPECT--
|
||||
int(10)
|
21
Zend/tests/type_declarations/typed_properties_042.phpt
Normal file
21
Zend/tests/type_declarations/typed_properties_042.phpt
Normal file
@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Proper source duplication on assignment to typed property
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar;
|
||||
}
|
||||
|
||||
$foo = new Foo();
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$foo->bar = "5";
|
||||
var_dump($foo->bar);
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
int(5)
|
||||
int(5)
|
||||
int(5)
|
||||
int(5)
|
||||
int(5)
|
53
Zend/tests/type_declarations/typed_properties_043.phpt
Normal file
53
Zend/tests/type_declarations/typed_properties_043.phpt
Normal file
@ -0,0 +1,53 @@
|
||||
--TEST--
|
||||
Trying to assign to a static 'self' typed property on a trait must not fixate the type to the trait
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
trait Test {
|
||||
public static self $selfProp;
|
||||
public static ?self $selfNullProp;
|
||||
public static parent $parentProp;
|
||||
}
|
||||
|
||||
try {
|
||||
Test::$selfProp = new stdClass;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
Test::$selfNullProp = new stdClass;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
Test::$parentProp = new stdClass;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
Test::$selfNullProp = null;
|
||||
var_dump(Test::$selfNullProp);
|
||||
|
||||
class Foo {}
|
||||
class Bar extends Foo {
|
||||
use Test;
|
||||
}
|
||||
|
||||
Bar::$selfProp = new Bar;
|
||||
Bar::$selfNullProp = new Bar;
|
||||
Bar::$parentProp = new Foo;
|
||||
|
||||
var_dump(Bar::$selfProp, Bar::$selfNullProp, Bar::$parentProp);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot write a value to a 'self' typed static property of a trait
|
||||
Cannot write a non-null value to a 'self' typed static property of a trait
|
||||
Cannot access parent:: when current class scope has no parent
|
||||
NULL
|
||||
object(Bar)#3 (0) {
|
||||
}
|
||||
object(Bar)#2 (0) {
|
||||
}
|
||||
object(Foo)#4 (0) {
|
||||
}
|
58
Zend/tests/type_declarations/typed_properties_044.phpt
Normal file
58
Zend/tests/type_declarations/typed_properties_044.phpt
Normal file
@ -0,0 +1,58 @@
|
||||
--TEST--
|
||||
Test increment functions on typed property references
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64 bit platform only"); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$foo = new class {
|
||||
public ?int $bar;
|
||||
};
|
||||
|
||||
$bar = &$foo->bar;
|
||||
|
||||
$bar *= 1;
|
||||
|
||||
var_dump($bar--);
|
||||
var_dump(--$bar);
|
||||
var_dump(++$bar);
|
||||
var_dump($bar++);
|
||||
|
||||
$bar = PHP_INT_MAX;
|
||||
|
||||
try {
|
||||
var_dump($bar++);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump(++$bar);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
$bar = PHP_INT_MIN;
|
||||
|
||||
|
||||
try {
|
||||
var_dump($bar--);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
var_dump(--$bar);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(0)
|
||||
int(-2)
|
||||
int(-1)
|
||||
int(-1)
|
||||
Cannot increment a reference held by property class@anonymous::$bar of type ?int past its maximal value
|
||||
Cannot increment a reference held by property class@anonymous::$bar of type ?int past its maximal value
|
||||
Cannot decrement a reference held by property class@anonymous::$bar of type ?int past its minimal value
|
||||
Cannot decrement a reference held by property class@anonymous::$bar of type ?int past its minimal value
|
51
Zend/tests/type_declarations/typed_properties_045.phpt
Normal file
51
Zend/tests/type_declarations/typed_properties_045.phpt
Normal file
@ -0,0 +1,51 @@
|
||||
--TEST--
|
||||
foreach() must return properly typed references
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bar = 0;
|
||||
public float $baz = 0.5;
|
||||
private float $privateProp = 0.5;
|
||||
|
||||
public function test() {
|
||||
foreach ($this as $k => &$val) {
|
||||
if ($k == 'privateProp') {
|
||||
var_dump($val);
|
||||
$val = 20;
|
||||
var_dump($val);
|
||||
try {
|
||||
$val = [];
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$foo = new Foo;
|
||||
foreach ($foo as $k => &$val) {
|
||||
var_dump($val);
|
||||
|
||||
$val = 20;
|
||||
var_dump($foo->$k);
|
||||
|
||||
try {
|
||||
$val = [];
|
||||
var_dump($foo->$k);
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
$foo->test();
|
||||
?>
|
||||
--EXPECT--
|
||||
int(0)
|
||||
int(20)
|
||||
Cannot assign array to reference held by property Foo::$bar of type int
|
||||
float(0.5)
|
||||
float(20)
|
||||
Cannot assign array to reference held by property Foo::$baz of type float
|
||||
float(0.5)
|
||||
float(20)
|
||||
Cannot assign array to reference held by property Foo::$privateProp of type float
|
29
Zend/tests/type_declarations/typed_properties_046.phpt
Normal file
29
Zend/tests/type_declarations/typed_properties_046.phpt
Normal file
@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Memory leaks on wrong assignment to typed property
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $bbb;
|
||||
}
|
||||
|
||||
function foo() {
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
function bar() {
|
||||
return str_repeat("b", 3);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
try {
|
||||
foo()->{bar()} = str_repeat("a", 3);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
--EXPECT--
|
||||
Typed property Foo::$bbb must be int, string used
|
||||
Typed property Foo::$bbb must be int, string used
|
||||
Typed property Foo::$bbb must be int, string used
|
||||
Typed property Foo::$bbb must be int, string used
|
||||
Typed property Foo::$bbb must be int, string used
|
40
Zend/tests/type_declarations/typed_properties_047.phpt
Normal file
40
Zend/tests/type_declarations/typed_properties_047.phpt
Normal file
@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
Nullable typed property
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public ?int $foo = null;
|
||||
}
|
||||
|
||||
$x = new Foo();
|
||||
var_dump($x);
|
||||
var_dump($x->foo);
|
||||
|
||||
$x->foo = 5;
|
||||
var_dump($x->foo);
|
||||
|
||||
$x->foo = null;
|
||||
var_dump($x->foo);
|
||||
|
||||
unset($x->foo);
|
||||
try {
|
||||
var_dump($x->foo);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage()."\n";
|
||||
}
|
||||
try {
|
||||
$x->foo = "ops";
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage()."\n";
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(Foo)#1 (1) {
|
||||
["foo"]=>
|
||||
NULL
|
||||
}
|
||||
NULL
|
||||
int(5)
|
||||
NULL
|
||||
Typed property Foo::$foo must not be accessed before initialization
|
||||
Typed property Foo::$foo must be int or null, string used
|
17
Zend/tests/type_declarations/typed_properties_048.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_048.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Parent private property types must be ignored
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
private $prop = "1";
|
||||
}
|
||||
class B extends A {
|
||||
private int $prop = 2;
|
||||
}
|
||||
|
||||
var_dump((function () { return $this->prop; })->call(new B));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(2)
|
10
Zend/tests/type_declarations/typed_properties_049.phpt
Normal file
10
Zend/tests/type_declarations/typed_properties_049.phpt
Normal file
@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
Nullable typed property
|
||||
--FILE--
|
||||
<?php
|
||||
class Foo {
|
||||
public int $foo = null;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Default value for property of type int may not be null. Use the nullable type ?int to allow null default value in %s on line %d
|
19
Zend/tests/type_declarations/typed_properties_050.phpt
Normal file
19
Zend/tests/type_declarations/typed_properties_050.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Weak casts must not overwrite source variables
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$b = 1;
|
||||
$a = "$b";
|
||||
class A { public int $a; }
|
||||
$o = new A;
|
||||
$o->a = $b;
|
||||
var_dump($o, $a);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(A)#1 (1) {
|
||||
["a"]=>
|
||||
int(1)
|
||||
}
|
||||
string(1) "1"
|
27
Zend/tests/type_declarations/typed_properties_051.phpt
Normal file
27
Zend/tests/type_declarations/typed_properties_051.phpt
Normal file
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Weak casts must not leak
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public string $a;
|
||||
}
|
||||
class B {
|
||||
function __toString() {
|
||||
return str_repeat("ok", 2);
|
||||
}
|
||||
}
|
||||
class C {
|
||||
}
|
||||
$o = new A;
|
||||
$o->a = new B;
|
||||
var_dump($o->a);
|
||||
try {
|
||||
$o->a = new C;
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage()."\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
string(4) "okok"
|
||||
Typed property A::$a must be string, C used
|
34
Zend/tests/type_declarations/typed_properties_052.phpt
Normal file
34
Zend/tests/type_declarations/typed_properties_052.phpt
Normal file
@ -0,0 +1,34 @@
|
||||
--TEST--
|
||||
Class properties declared in eval() must not leak
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
eval(<<<'EOF'
|
||||
class A {
|
||||
public A $a1;
|
||||
public \B $b1;
|
||||
public Foo\C $c1;
|
||||
public ?A $a2;
|
||||
public ?\B $b2;
|
||||
public ?Foo\C $c2;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$obj = new A;
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECT--
|
||||
object(A)#1 (0) {
|
||||
["a1"]=>
|
||||
uninitialized(A)
|
||||
["b1"]=>
|
||||
uninitialized(B)
|
||||
["c1"]=>
|
||||
uninitialized(Foo\C)
|
||||
["a2"]=>
|
||||
uninitialized(?A)
|
||||
["b2"]=>
|
||||
uninitialized(?B)
|
||||
["c2"]=>
|
||||
uninitialized(?Foo\C)
|
||||
}
|
12
Zend/tests/type_declarations/typed_properties_053.phpt
Normal file
12
Zend/tests/type_declarations/typed_properties_053.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
Typed properties disallow callable
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
public callable $a;
|
||||
}
|
||||
$obj = new A;
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Property A::$a cannot have type callable in %s on line %d
|
12
Zend/tests/type_declarations/typed_properties_054.phpt
Normal file
12
Zend/tests/type_declarations/typed_properties_054.phpt
Normal file
@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
Typed properties disallow callable (nullable variant)
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
public ?callable $a;
|
||||
}
|
||||
$obj = new A;
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Property A::$a cannot have type callable in %s on line %d
|
29
Zend/tests/type_declarations/typed_properties_055.phpt
Normal file
29
Zend/tests/type_declarations/typed_properties_055.phpt
Normal file
@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Test assign to typed property taken by reference
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
public $foo = 1;
|
||||
public int $bar = 2;
|
||||
}
|
||||
class B {
|
||||
public A $a;
|
||||
}
|
||||
$f = function (&$n) {
|
||||
var_dump($n);
|
||||
$n = "ops";
|
||||
};
|
||||
$o = new B;
|
||||
$o->a = new A;
|
||||
$f($o->a->foo);
|
||||
$f($o->a->bar);
|
||||
?>
|
||||
--EXPECTF--
|
||||
int(1)
|
||||
int(2)
|
||||
|
||||
Fatal error: Uncaught TypeError: Cannot assign string to reference held by property A::$bar of type int in %s:%d
|
||||
Stack trace:
|
||||
#0 %s(%d): {closure}(2)
|
||||
#1 {main}
|
||||
thrown in %s on line %d
|
23
Zend/tests/type_declarations/typed_properties_056.phpt
Normal file
23
Zend/tests/type_declarations/typed_properties_056.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Type change in assign_op (use-after-free)
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class A {
|
||||
public string $foo;
|
||||
}
|
||||
|
||||
$o = new A;
|
||||
$o->foo = "1" . str_repeat("0", 2);
|
||||
try {
|
||||
$o->foo += 5;
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
var_dump($o->foo);
|
||||
unset($o);
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property A::$foo must be string, int used
|
||||
string(3) "100"
|
31
Zend/tests/type_declarations/typed_properties_057.phpt
Normal file
31
Zend/tests/type_declarations/typed_properties_057.phpt
Normal file
@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Type change in pre/post-increment (use-after-free)
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
class A {
|
||||
public string $foo;
|
||||
}
|
||||
|
||||
$o = new A;
|
||||
$o->foo = "1" . str_repeat("0", 2);
|
||||
try {
|
||||
$x = ++$o->foo;
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
var_dump($o->foo);
|
||||
try {
|
||||
$x = $o->foo++;
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
var_dump($o->foo);
|
||||
unset($o);
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property A::$foo must be string, int used
|
||||
string(3) "100"
|
||||
Typed property A::$foo must be string, int used
|
||||
string(3) "100"
|
32
Zend/tests/type_declarations/typed_properties_058.phpt
Normal file
32
Zend/tests/type_declarations/typed_properties_058.phpt
Normal file
@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
Constants in default values of properties
|
||||
--FILE--
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
define("FOO", 5);
|
||||
|
||||
class A {
|
||||
public int $foo = FOO;
|
||||
}
|
||||
|
||||
class B {
|
||||
public string $foo = FOO;
|
||||
}
|
||||
|
||||
$o = new A();
|
||||
var_dump($o->foo);
|
||||
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
try {
|
||||
$o = new B();
|
||||
var_dump($o->foo);
|
||||
} catch (Throwable $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
int(5)
|
||||
Typed property B::$foo must be string, int used
|
||||
Typed property B::$foo must be string, int used
|
29
Zend/tests/type_declarations/typed_properties_059.phpt
Normal file
29
Zend/tests/type_declarations/typed_properties_059.phpt
Normal file
@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Nullable typed properties in traits
|
||||
--FILE--
|
||||
<?php
|
||||
trait T {
|
||||
public int $a1;
|
||||
public ?int $b1;
|
||||
}
|
||||
|
||||
class A {
|
||||
use T;
|
||||
public int $a2;
|
||||
public ?int $b2;
|
||||
}
|
||||
|
||||
$x = new A;
|
||||
var_dump($x);
|
||||
?>
|
||||
--EXPECT--
|
||||
object(A)#1 (0) {
|
||||
["a2"]=>
|
||||
uninitialized(int)
|
||||
["b2"]=>
|
||||
uninitialized(?int)
|
||||
["a1"]=>
|
||||
uninitialized(int)
|
||||
["b1"]=>
|
||||
uninitialized(?int)
|
||||
}
|
22
Zend/tests/type_declarations/typed_properties_060.phpt
Normal file
22
Zend/tests/type_declarations/typed_properties_060.phpt
Normal file
@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
Test typed properties work fine with simple inheritance
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public int $a = 1;
|
||||
}
|
||||
class B extends A {}
|
||||
|
||||
$o = new B;
|
||||
var_dump($o->a);
|
||||
$o->a = "a";
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
int(1)
|
||||
|
||||
Fatal error: Uncaught TypeError: Typed property A::$a must be int, string used in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
58
Zend/tests/type_declarations/typed_properties_061.phpt
Normal file
58
Zend/tests/type_declarations/typed_properties_061.phpt
Normal file
@ -0,0 +1,58 @@
|
||||
--TEST--
|
||||
Typed property on overloaded by-ref property
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE == 4) die("SKIP: 64 bit test"); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public int $foo = 1;
|
||||
|
||||
function &__get($x) {
|
||||
return $this->foo;
|
||||
}
|
||||
|
||||
function __set($x, $y) {
|
||||
echo "set($y)\n";
|
||||
}
|
||||
};
|
||||
|
||||
$a->_ += 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_ .= "1";
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_ .= "e50";
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_--;
|
||||
var_dump($a->foo);
|
||||
|
||||
--$a->_;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->foo = PHP_INT_MAX;
|
||||
|
||||
$a->_++;
|
||||
var_dump($a->foo);
|
||||
|
||||
++$a->_;
|
||||
var_dump($a->foo);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
set(2)
|
||||
int(1)
|
||||
set(11)
|
||||
int(1)
|
||||
set(1e50)
|
||||
int(1)
|
||||
set(0)
|
||||
int(1)
|
||||
set(0)
|
||||
int(1)
|
||||
set(9.2233720368548E+18)
|
||||
int(9223372036854775807)
|
||||
set(9.2233720368548E+18)
|
||||
int(9223372036854775807)
|
81
Zend/tests/type_declarations/typed_properties_062.phpt
Normal file
81
Zend/tests/type_declarations/typed_properties_062.phpt
Normal file
@ -0,0 +1,81 @@
|
||||
--TEST--
|
||||
Typed property on by-ref property
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public int $foo = 1;
|
||||
public $_;
|
||||
};
|
||||
|
||||
$a->_ = &$a->foo;
|
||||
|
||||
$a->_ += 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_ .= "1";
|
||||
var_dump($a->foo);
|
||||
|
||||
try {
|
||||
$a->_ .= "e50";
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_--;
|
||||
var_dump($a->foo);
|
||||
|
||||
--$a->_;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->foo = PHP_INT_MIN;
|
||||
|
||||
try {
|
||||
$a->_--;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
--$a->_;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$a->foo = PHP_INT_MAX;
|
||||
|
||||
try {
|
||||
$a->_++;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
++$a->_;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$a->_ = 0;
|
||||
try {
|
||||
$a->_ = [];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->_ = 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(2)
|
||||
int(21)
|
||||
Cannot assign string to reference held by property class@anonymous::$foo of type int
|
||||
int(21)
|
||||
int(20)
|
||||
int(19)
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot assign array to reference held by property class@anonymous::$foo of type int
|
||||
int(0)
|
||||
int(1)
|
80
Zend/tests/type_declarations/typed_properties_063.phpt
Normal file
80
Zend/tests/type_declarations/typed_properties_063.phpt
Normal file
@ -0,0 +1,80 @@
|
||||
--TEST--
|
||||
Typed property on by-ref variable
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public int $foo = 1;
|
||||
};
|
||||
|
||||
$_ = &$a->foo;
|
||||
|
||||
$_ += 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
$_ .= "1";
|
||||
var_dump($a->foo);
|
||||
|
||||
try {
|
||||
$_ .= "e50";
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$_--;
|
||||
var_dump($a->foo);
|
||||
|
||||
--$_;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->foo = PHP_INT_MIN;
|
||||
|
||||
try {
|
||||
$_--;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
--$_;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$a->foo = PHP_INT_MAX;
|
||||
|
||||
try {
|
||||
$_++;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
++$_;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$_ = 0;
|
||||
try {
|
||||
$_ = [];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$_ = 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(2)
|
||||
int(21)
|
||||
Cannot assign string to reference held by property class@anonymous::$foo of type int
|
||||
int(21)
|
||||
int(20)
|
||||
int(19)
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot assign array to reference held by property class@anonymous::$foo of type int
|
||||
int(0)
|
||||
int(1)
|
80
Zend/tests/type_declarations/typed_properties_064.phpt
Normal file
80
Zend/tests/type_declarations/typed_properties_064.phpt
Normal file
@ -0,0 +1,80 @@
|
||||
--TEST--
|
||||
Typed property on by-ref array value
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public int $foo = 1;
|
||||
};
|
||||
|
||||
$_ = [&$a->foo];
|
||||
|
||||
$_[0] += 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
$_[0] .= "1";
|
||||
var_dump($a->foo);
|
||||
|
||||
try {
|
||||
$_[0] .= "e50";
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$_[0]--;
|
||||
var_dump($a->foo);
|
||||
|
||||
--$_[0];
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->foo = PHP_INT_MIN;
|
||||
|
||||
try {
|
||||
$_[0]--;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
--$_[0];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$a->foo = PHP_INT_MAX;
|
||||
|
||||
try {
|
||||
$_[0]++;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
++$_[0];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$_[0] = 0;
|
||||
try {
|
||||
$_[0] = [];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($a->foo);
|
||||
|
||||
$_[0] = 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(2)
|
||||
int(21)
|
||||
Cannot assign string to reference held by property class@anonymous::$foo of type int
|
||||
int(21)
|
||||
int(20)
|
||||
int(19)
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot assign array to reference held by property class@anonymous::$foo of type int
|
||||
int(0)
|
||||
int(1)
|
71
Zend/tests/type_declarations/typed_properties_065.phpt
Normal file
71
Zend/tests/type_declarations/typed_properties_065.phpt
Normal file
@ -0,0 +1,71 @@
|
||||
--TEST--
|
||||
Typed property on by-ref array dimension
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class implements ArrayAccess {
|
||||
public int $foo = 1;
|
||||
|
||||
function offsetExists($o) { return 1; }
|
||||
function &offsetGet($o) { return $this->foo; }
|
||||
function offsetSet($o, $v) { print "offsetSet($v)\n"; }
|
||||
function offsetUnset($o) { print "offsetUnset() ?!?"; }
|
||||
};
|
||||
|
||||
$a[0] += 1;
|
||||
var_dump($a->foo);
|
||||
|
||||
$a[0] .= "1";
|
||||
var_dump($a->foo);
|
||||
|
||||
$a[0] .= "e50";
|
||||
var_dump($a->foo);
|
||||
|
||||
$a[0]--;
|
||||
var_dump($a->foo);
|
||||
|
||||
--$a[0];
|
||||
var_dump($a->foo);
|
||||
|
||||
$a->foo = PHP_INT_MIN;
|
||||
|
||||
try {
|
||||
$a[0]--;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
--$a[0];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
$a->foo = PHP_INT_MAX;
|
||||
|
||||
try {
|
||||
$a[0]++;
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
try {
|
||||
++$a[0];
|
||||
} catch (Error $e) { echo $e->getMessage(), "\n"; }
|
||||
echo gettype($a->foo),"\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
offsetSet(2)
|
||||
int(1)
|
||||
offsetSet(11)
|
||||
int(1)
|
||||
offsetSet(1e50)
|
||||
int(1)
|
||||
int(0)
|
||||
int(-1)
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot decrement a reference held by property class@anonymous::$foo of type int past its minimal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
||||
Cannot increment a reference held by property class@anonymous::$foo of type int past its maximal value
|
||||
integer
|
21
Zend/tests/type_declarations/typed_properties_066.phpt
Normal file
21
Zend/tests/type_declarations/typed_properties_066.phpt
Normal file
@ -0,0 +1,21 @@
|
||||
--TEST--
|
||||
Typed property assignment must not overwrite constants
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public float $x = 0.0;
|
||||
};
|
||||
|
||||
$x = new Foo;
|
||||
$y =& $x->x;
|
||||
$y = 4;
|
||||
var_dump($x, 4); /* Optimizer will merge both "4" constants, making it immediately visible */
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Foo)#1 (1) {
|
||||
["x"]=>
|
||||
&float(4)
|
||||
}
|
||||
int(4)
|
36
Zend/tests/type_declarations/typed_properties_067.phpt
Normal file
36
Zend/tests/type_declarations/typed_properties_067.phpt
Normal file
@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Iterable typed properties must be accepted to by-ref array arguments
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$obj = new class {
|
||||
public ?iterable $it = null;
|
||||
};
|
||||
|
||||
function arr(?array &$arr) {
|
||||
$arr = [1];
|
||||
}
|
||||
|
||||
arr($obj->it);
|
||||
var_dump($obj->it);
|
||||
array_shift($obj->it);
|
||||
var_dump($obj->it);
|
||||
parse_str("foo=bar", $obj->it);
|
||||
var_dump($obj->it);
|
||||
$obj->it = [];
|
||||
var_dump($obj->it);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(1)
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
array(1) {
|
||||
["foo"]=>
|
||||
string(3) "bar"
|
||||
}
|
||||
array(0) {
|
||||
}
|
87
Zend/tests/type_declarations/typed_properties_068.phpt
Normal file
87
Zend/tests/type_declarations/typed_properties_068.phpt
Normal file
@ -0,0 +1,87 @@
|
||||
--TEST--
|
||||
Test typed static property by ref
|
||||
--FILE--
|
||||
<?php
|
||||
function &ref($a = null) {
|
||||
static $f;
|
||||
if ($a !== null) $f = function &() use (&$a) { return $a; };
|
||||
return $f();
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public static int $i;
|
||||
public static string $s = "x";
|
||||
}
|
||||
|
||||
Foo::$i = &ref(5);
|
||||
var_dump(Foo::$i);
|
||||
|
||||
$i = &Foo::$i;
|
||||
$i = 2;
|
||||
var_dump($i, Foo::$i);
|
||||
|
||||
$i = "3";
|
||||
var_dump($i, Foo::$i);
|
||||
|
||||
Foo::$i = "4";
|
||||
var_dump($i, Foo::$i);
|
||||
|
||||
try {
|
||||
$i = null;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump($i, Foo::$i);
|
||||
|
||||
try {
|
||||
Foo::$i = null;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump($i, Foo::$i);
|
||||
|
||||
Foo::$s = &ref(5);
|
||||
var_dump(Foo::$s, ref());
|
||||
|
||||
Foo::$i = &ref("0");
|
||||
var_dump(Foo::$i, ref());
|
||||
|
||||
try {
|
||||
Foo::$i = &ref("x");
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(Foo::$i, ref());
|
||||
|
||||
try {
|
||||
Foo::$i = &Foo::$s;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(Foo::$i, Foo::$s);
|
||||
|
||||
try {
|
||||
Foo::$s = &Foo::$i;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(Foo::$i, Foo::$s);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(5)
|
||||
int(2)
|
||||
int(2)
|
||||
int(3)
|
||||
int(3)
|
||||
int(4)
|
||||
int(4)
|
||||
Cannot assign null to reference held by property Foo::$i of type int
|
||||
int(4)
|
||||
int(4)
|
||||
Typed property Foo::$i must be int, null used
|
||||
int(4)
|
||||
int(4)
|
||||
string(1) "5"
|
||||
string(1) "5"
|
||||
int(0)
|
||||
int(0)
|
||||
Typed property Foo::$i must be int, string used
|
||||
int(0)
|
||||
string(1) "x"
|
||||
Reference with value of type string held by property Foo::$s of type string is not compatible with property Foo::$i of type int
|
||||
int(0)
|
||||
string(1) "5"
|
||||
Reference with value of type int held by property Foo::$i of type int is not compatible with property Foo::$s of type string
|
||||
int(0)
|
||||
string(1) "5"
|
27
Zend/tests/type_declarations/typed_properties_069.phpt
Normal file
27
Zend/tests/type_declarations/typed_properties_069.phpt
Normal file
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Test assign of invalid string to typed static int property
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function &nonNumericStringRef() {
|
||||
static $a = "x";
|
||||
return $a;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public static int $i;
|
||||
}
|
||||
|
||||
try {
|
||||
Foo::$i = &nonNumericStringRef();
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
try {
|
||||
var_dump(Foo::$i);
|
||||
} catch (Error $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(nonNumericStringRef());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property Foo::$i must be int, string used
|
||||
Typed static property Foo::$i must not be accessed before initialization
|
||||
string(1) "x"
|
49
Zend/tests/type_declarations/typed_properties_070.phpt
Normal file
49
Zend/tests/type_declarations/typed_properties_070.phpt
Normal file
@ -0,0 +1,49 @@
|
||||
--TEST--
|
||||
Test typed static property with assign op operators
|
||||
--FILE--
|
||||
<?php
|
||||
function &stringRef() {
|
||||
static $a = "1";
|
||||
$b = $a;
|
||||
$a = &$b;
|
||||
return $a;
|
||||
}
|
||||
|
||||
class Foo {
|
||||
public static int $i = 0;
|
||||
public static string $s = "1";
|
||||
}
|
||||
|
||||
Foo::$s .= "1";
|
||||
var_dump(Foo::$s);
|
||||
|
||||
Foo::$s += 2;
|
||||
var_dump(Foo::$s);
|
||||
|
||||
Foo::$s = &stringRef();
|
||||
Foo::$s .= 2;
|
||||
var_dump(Foo::$s);
|
||||
|
||||
Foo::$i += stringRef();
|
||||
var_dump(Foo::$i);
|
||||
|
||||
try {
|
||||
Foo::$i += PHP_INT_MAX;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(Foo::$i);
|
||||
|
||||
try {
|
||||
Foo::$i .= PHP_INT_MAX;
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump(Foo::$i);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(2) "11"
|
||||
string(2) "13"
|
||||
string(2) "12"
|
||||
int(1)
|
||||
Typed property Foo::$i must be int, float used
|
||||
int(1)
|
||||
Typed property Foo::$i must be int, string used
|
||||
int(1)
|
36
Zend/tests/type_declarations/typed_properties_071.phpt
Normal file
36
Zend/tests/type_declarations/typed_properties_071.phpt
Normal file
@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Test assignment to typed reference with weak type conversion
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public string $x = "x";
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
var_dump($test);
|
||||
$y = "y";
|
||||
$test->x = &$y;
|
||||
var_dump($y, $test);
|
||||
|
||||
$z = 42;
|
||||
$y = $z;
|
||||
var_dump($y, $z, $test);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Test)#1 (1) {
|
||||
["x"]=>
|
||||
string(1) "x"
|
||||
}
|
||||
string(1) "y"
|
||||
object(Test)#1 (1) {
|
||||
["x"]=>
|
||||
&string(1) "y"
|
||||
}
|
||||
string(2) "42"
|
||||
int(42)
|
||||
object(Test)#1 (1) {
|
||||
["x"]=>
|
||||
&string(2) "42"
|
||||
}
|
24
Zend/tests/type_declarations/typed_properties_072.phpt
Normal file
24
Zend/tests/type_declarations/typed_properties_072.phpt
Normal file
@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
Typed property must cast when used with __get()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public int $val;
|
||||
|
||||
public function __get($name) {
|
||||
return "42";
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
var_dump($test);
|
||||
var_dump($test->val);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Test)#1 (0) {
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
int(42)
|
44
Zend/tests/type_declarations/typed_properties_073.phpt
Normal file
44
Zend/tests/type_declarations/typed_properties_073.phpt
Normal file
@ -0,0 +1,44 @@
|
||||
--TEST--
|
||||
Typed property must cast when used with &__get()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public $prop = "42";
|
||||
public int $val;
|
||||
|
||||
public function &__get($name) {
|
||||
return $this->prop;
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
var_dump($test);
|
||||
var_dump($val = &$test->val);
|
||||
var_dump($test);
|
||||
|
||||
$test->prop = "x";
|
||||
var_dump($test, $val);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Test)#1 (1) {
|
||||
["prop"]=>
|
||||
string(2) "42"
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
int(42)
|
||||
object(Test)#1 (1) {
|
||||
["prop"]=>
|
||||
&int(42)
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
object(Test)#1 (1) {
|
||||
["prop"]=>
|
||||
&string(1) "x"
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
string(1) "x"
|
41
Zend/tests/type_declarations/typed_properties_074.phpt
Normal file
41
Zend/tests/type_declarations/typed_properties_074.phpt
Normal file
@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
Typed property must be compatible when returned via &__get()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public $prop = "x";
|
||||
public int $val;
|
||||
|
||||
public function &__get($name) {
|
||||
return $this->prop;
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
$dummyRef = &$test->prop;
|
||||
var_dump($test);
|
||||
try {
|
||||
var_dump($test->val);
|
||||
} catch (TypeError $e) { print $e->getMessage()."\n"; }
|
||||
var_dump($test);
|
||||
|
||||
$test->prop = "y";
|
||||
var_dump($test->prop);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Test)#1 (1) {
|
||||
["prop"]=>
|
||||
&string(1) "x"
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
Typed property Test::$val must be int, string used
|
||||
object(Test)#1 (1) {
|
||||
["prop"]=>
|
||||
&string(1) "x"
|
||||
["val"]=>
|
||||
uninitialized(int)
|
||||
}
|
||||
string(1) "y"
|
53
Zend/tests/type_declarations/typed_properties_075.phpt
Normal file
53
Zend/tests/type_declarations/typed_properties_075.phpt
Normal file
@ -0,0 +1,53 @@
|
||||
--TEST--
|
||||
Test typed properties overflowing
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE == 4) die("SKIP: 64 bit test"); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public static int $bar = PHP_INT_MAX;
|
||||
};
|
||||
|
||||
try {
|
||||
Foo::$bar++;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump(Foo::$bar);
|
||||
|
||||
try {
|
||||
Foo::$bar += 1;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump(Foo::$bar);
|
||||
|
||||
try {
|
||||
++Foo::$bar;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump(Foo::$bar);
|
||||
|
||||
try {
|
||||
Foo::$bar = Foo::$bar + 1;
|
||||
} catch(TypeError $t) {
|
||||
var_dump($t->getMessage());
|
||||
}
|
||||
|
||||
var_dump(Foo::$bar);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(70) "Cannot increment property Foo::$bar of type int past its maximal value"
|
||||
int(9223372036854775807)
|
||||
string(48) "Typed property Foo::$bar must be int, float used"
|
||||
int(9223372036854775807)
|
||||
string(70) "Cannot increment property Foo::$bar of type int past its maximal value"
|
||||
int(9223372036854775807)
|
||||
string(48) "Typed property Foo::$bar must be int, float used"
|
||||
int(9223372036854775807)
|
71
Zend/tests/type_declarations/typed_properties_076.phpt
Normal file
71
Zend/tests/type_declarations/typed_properties_076.phpt
Normal file
@ -0,0 +1,71 @@
|
||||
--TEST--
|
||||
Computation of intersection types for typed reference to typed property assignments
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {}
|
||||
class B extends A {}
|
||||
|
||||
class Test {
|
||||
public int $int;
|
||||
public float $float;
|
||||
public ?int $nint;
|
||||
public ?string $nstring;
|
||||
public array $array;
|
||||
public object $object;
|
||||
public iterable $iterable;
|
||||
public Iterator $Iterator;
|
||||
public A $A;
|
||||
public B $B;
|
||||
}
|
||||
|
||||
function invalid(Test $test, string $prop1, string $prop2, $value) {
|
||||
try {
|
||||
$test->$prop2 = $value;
|
||||
$test->$prop1 =& $test->$prop2;
|
||||
echo "Invalid assignment $prop1 =& $prop2 did not error\n";
|
||||
} catch (TypeError $e) {}
|
||||
try {
|
||||
$test->$prop1 = $value;
|
||||
$test->$prop2 =& $test->$prop1;
|
||||
echo "Invalid assignment $prop2 =& $prop1 did not error\n";
|
||||
} catch (TypeError $e) {}
|
||||
}
|
||||
|
||||
function valid(Test $test, string $prop1, string $prop2, $value) {
|
||||
try {
|
||||
$test->$prop2 = $value;
|
||||
$test->$prop1 =& $test->$prop2;
|
||||
} catch (TypeError $e) {
|
||||
echo "Valid assignment $prop1 =& $prop2 threw {$e->getMessage()}\n";
|
||||
}
|
||||
try {
|
||||
$test->$prop1 = $value;
|
||||
$test->$prop2 =& $test->$prop1;
|
||||
} catch (TypeError $e) {
|
||||
echo "Valid assignment $prop2 =& $prop1 threw {$e->getMessage()}\n";
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
invalid($test, 'int', 'float', 42.0);
|
||||
valid($test, 'int', 'nint', 42);
|
||||
invalid($test, 'int', 'nint', null);
|
||||
valid($test, 'nint', 'nstring', null);
|
||||
invalid($test, 'nint', 'nstring', '42');
|
||||
valid($test, 'A', 'A', new A);
|
||||
valid($test, 'A', 'B', new B);
|
||||
invalid($test, 'A', 'B', new A);
|
||||
valid($test, 'iterable', 'array', [1, 2, 3]);
|
||||
valid($test, 'A', 'object', new A);
|
||||
invalid($test, 'A', 'object', new Test);
|
||||
valid($test, 'iterable', 'Iterator', new ArrayIterator);
|
||||
invalid($test, 'Iterator', 'iterable', [1, 2, 3]);
|
||||
valid($test, 'object', 'iterable', new ArrayIterator);
|
||||
invalid($test, 'iterable', 'object', new stdClass);
|
||||
|
||||
echo "Done\n";
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Done
|
18
Zend/tests/type_declarations/typed_properties_077.phpt
Normal file
18
Zend/tests/type_declarations/typed_properties_077.phpt
Normal file
@ -0,0 +1,18 @@
|
||||
--TEST--
|
||||
Converted values shall be returned and not the original value upon property assignment
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public int $i;
|
||||
public string $s;
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
var_dump($test->i = "42");
|
||||
var_dump($test->s = 42);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(42)
|
||||
string(2) "42"
|
59
Zend/tests/type_declarations/typed_properties_078.phpt
Normal file
59
Zend/tests/type_declarations/typed_properties_078.phpt
Normal file
@ -0,0 +1,59 @@
|
||||
--TEST--
|
||||
Typed references must be kept track of and always be only the intersection of the types currently holding that reference
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$a = new class {
|
||||
public ?iterable $it = [];
|
||||
public ?array $a;
|
||||
public ?Traversable $t;
|
||||
};
|
||||
|
||||
$ref = &$a->it;
|
||||
$a->a = &$ref;
|
||||
|
||||
var_dump($ref);
|
||||
|
||||
try {
|
||||
$a->t = &$ref;
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($ref);
|
||||
|
||||
$a->it = [1]; // type is still assignable
|
||||
var_dump($ref);
|
||||
|
||||
try {
|
||||
$ref = new ArrayIterator();
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($ref instanceof ArrayIterator);
|
||||
|
||||
unset($a->a);
|
||||
|
||||
$ref = null;
|
||||
|
||||
$a->t = &$ref;
|
||||
|
||||
try {
|
||||
$ref = [];
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($ref instanceof ArrayIterator);
|
||||
|
||||
$ref = new ArrayIterator();
|
||||
var_dump($ref instanceof ArrayIterator);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(0) {
|
||||
}
|
||||
string(89) "Typed property class@anonymous::$t must be an instance of Traversable or null, array used"
|
||||
array(0) {
|
||||
}
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(1)
|
||||
}
|
||||
string(92) "Cannot assign ArrayIterator to reference held by property class@anonymous::$a of type ?array"
|
||||
bool(false)
|
||||
string(90) "Cannot assign array to reference held by property class@anonymous::$t of type ?Traversable"
|
||||
bool(false)
|
||||
bool(true)
|
33
Zend/tests/type_declarations/typed_properties_079.phpt
Normal file
33
Zend/tests/type_declarations/typed_properties_079.phpt
Normal file
@ -0,0 +1,33 @@
|
||||
--TEST--
|
||||
Test static typed properties with references
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
static iterable $it = [];
|
||||
static ?array $a;
|
||||
}
|
||||
|
||||
A::$a = &A::$it;
|
||||
|
||||
try {
|
||||
A::$it = new ArrayIterator();
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump(A::$it);
|
||||
|
||||
A::$a = &$a;
|
||||
|
||||
A::$it = new ArrayIterator();
|
||||
|
||||
try {
|
||||
$a = 1;
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($a);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(78) "Cannot assign ArrayIterator to reference held by property A::$a of type ?array"
|
||||
array(0) {
|
||||
}
|
||||
string(68) "Cannot assign int to reference held by property A::$a of type ?array"
|
||||
NULL
|
36
Zend/tests/type_declarations/typed_properties_080.phpt
Normal file
36
Zend/tests/type_declarations/typed_properties_080.phpt
Normal file
@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Access to typed static properties before initialization
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public static int $a;
|
||||
protected static int $b;
|
||||
private static int $c;
|
||||
|
||||
static function run() {
|
||||
try {
|
||||
self::$a;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
self::$b;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
self::$c;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Test::run();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed static property Test::$a must not be accessed before initialization
|
||||
Typed static property Test::$b must not be accessed before initialization
|
||||
Typed static property Test::$c must not be accessed before initialization
|
22
Zend/tests/type_declarations/typed_properties_081.phpt
Normal file
22
Zend/tests/type_declarations/typed_properties_081.phpt
Normal file
@ -0,0 +1,22 @@
|
||||
--TEST--
|
||||
Clone must inherit typed references
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public int $x = 42;
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
$x =& $test->x;
|
||||
$test2 = clone $test;
|
||||
unset($test);
|
||||
try {
|
||||
$x = "foo";
|
||||
} catch (TypeError $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($test2->x);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot assign string to reference held by property Test::$x of type int
|
||||
int(42)
|
30
Zend/tests/type_declarations/typed_properties_082.phpt
Normal file
30
Zend/tests/type_declarations/typed_properties_082.phpt
Normal file
@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Test typed references to static properties
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public static int $x = 0;
|
||||
}
|
||||
|
||||
class Test2 extends Test {
|
||||
public static $y = 1;
|
||||
}
|
||||
|
||||
$x =& Test::$x;
|
||||
try {
|
||||
$x = "foo";
|
||||
} catch (TypeError $e) { echo $e->getMessage(), "\n"; }
|
||||
var_dump($x, Test::$x);
|
||||
|
||||
Test::$x =& Test2::$y; // remove the typed ref from $x
|
||||
$x = "foo";
|
||||
var_dump($x, Test::$x);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot assign string to reference held by property Test::$x of type int
|
||||
int(0)
|
||||
int(0)
|
||||
string(3) "foo"
|
||||
int(1)
|
80
Zend/tests/type_declarations/typed_properties_083.phpt
Normal file
80
Zend/tests/type_declarations/typed_properties_083.phpt
Normal file
@ -0,0 +1,80 @@
|
||||
--TEST--
|
||||
Test array promotion does not violate type restrictions
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Foo {
|
||||
public ?string $p;
|
||||
public ?iterable $i;
|
||||
public static ?string $s;
|
||||
public static ?array $a;
|
||||
}
|
||||
|
||||
$a = new Foo;
|
||||
|
||||
$a->i[] = 1;
|
||||
var_dump($a->i);
|
||||
|
||||
try {
|
||||
$a->p[] = "test";
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
try { // must be uninit
|
||||
var_dump($a->p); // WRONG!
|
||||
} catch (Error $e) { var_dump($e->getMessage()); }
|
||||
|
||||
$a->p = null;
|
||||
try {
|
||||
$a->p[] = "test";
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($a->p);
|
||||
|
||||
Foo::$a["bar"] = 2;
|
||||
var_dump(Foo::$a);
|
||||
|
||||
try {
|
||||
Foo::$s["baz"][] = "baz";
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
try { // must be uninit
|
||||
var_dump(Foo::$s);
|
||||
} catch (Error $e) { var_dump($e->getMessage()); }
|
||||
|
||||
Foo::$a = null;
|
||||
$ref = &Foo::$a;
|
||||
$ref[] = 3;
|
||||
var_dump($ref);
|
||||
|
||||
$ref = &$a->p;
|
||||
try {
|
||||
$ref[] = "bar";
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($ref);
|
||||
|
||||
try {
|
||||
$ref["baz"][] = "bar"; // indirect assign
|
||||
} catch (TypeError $e) { var_dump($e->getMessage()); }
|
||||
var_dump($ref);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(1)
|
||||
}
|
||||
string(71) "Cannot auto-initialize an array inside property Foo::$p of type ?string"
|
||||
string(65) "Typed property Foo::$p must not be accessed before initialization"
|
||||
string(71) "Cannot auto-initialize an array inside property Foo::$p of type ?string"
|
||||
NULL
|
||||
array(1) {
|
||||
["bar"]=>
|
||||
int(2)
|
||||
}
|
||||
string(71) "Cannot auto-initialize an array inside property Foo::$s of type ?string"
|
||||
string(72) "Typed static property Foo::$s must not be accessed before initialization"
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(3)
|
||||
}
|
||||
string(91) "Cannot auto-initialize an array inside a reference held by property Foo::$p of type ?string"
|
||||
NULL
|
||||
string(91) "Cannot auto-initialize an array inside a reference held by property Foo::$p of type ?string"
|
||||
NULL
|
25
Zend/tests/type_declarations/typed_properties_084.phpt
Normal file
25
Zend/tests/type_declarations/typed_properties_084.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Typed properties and class aliases
|
||||
--FILE--
|
||||
<?php
|
||||
eval(<<<'PHP'
|
||||
class Foo {}
|
||||
class_alias('Foo', 'Bar');
|
||||
PHP);
|
||||
|
||||
eval(<<<'PHP'
|
||||
class A {
|
||||
public Foo $prop;
|
||||
}
|
||||
PHP);
|
||||
|
||||
eval(<<<'PHP'
|
||||
class B extends A {
|
||||
public Bar $prop;
|
||||
}
|
||||
PHP);
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
17
Zend/tests/type_declarations/typed_properties_085.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_085.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Important properties with different types from traits
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
trait T1 {
|
||||
public int $prop;
|
||||
}
|
||||
trait T2 {
|
||||
public string $prop;
|
||||
}
|
||||
class C {
|
||||
use T1, T2;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: T1 and T2 define the same property ($prop) in the composition of C. However, the definition differs and is considered incompatible. Class was composed in %s on line %d
|
27
Zend/tests/type_declarations/typed_properties_086.phpt
Normal file
27
Zend/tests/type_declarations/typed_properties_086.phpt
Normal file
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Test typed properties with integer keys
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class T {
|
||||
// Class must have at least one property. Property must have a type.
|
||||
// Empty class or untyped property removes segfault
|
||||
public int $i;
|
||||
}
|
||||
|
||||
$t = new T;
|
||||
// $x must be undefined or a non-string type
|
||||
$x = 1;
|
||||
$t->$x = 2;
|
||||
$t->$x--;
|
||||
|
||||
var_dump($t);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(T)#1 (1) {
|
||||
["i"]=>
|
||||
uninitialized(int)
|
||||
["1"]=>
|
||||
int(1)
|
||||
}
|
15
Zend/tests/type_declarations/typed_properties_087.phpt
Normal file
15
Zend/tests/type_declarations/typed_properties_087.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Ensure null-initialization of nullable typed static property taken by reference
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public static ?int $a;
|
||||
}
|
||||
|
||||
$x =& A::$a;
|
||||
var_dump($x);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
NULL
|
30
Zend/tests/type_declarations/typed_properties_088.phpt
Normal file
30
Zend/tests/type_declarations/typed_properties_088.phpt
Normal file
@ -0,0 +1,30 @@
|
||||
--TEST--
|
||||
Check for correct invalidation of prop_info cache slots
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public int $prop;
|
||||
}
|
||||
class B {
|
||||
public $prop;
|
||||
}
|
||||
|
||||
function test($obj) {
|
||||
$obj->prop = "42";
|
||||
var_dump($obj);
|
||||
}
|
||||
|
||||
test(new A);
|
||||
test(new B);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(A)#1 (1) {
|
||||
["prop"]=>
|
||||
int(42)
|
||||
}
|
||||
object(B)#1 (1) {
|
||||
["prop"]=>
|
||||
string(2) "42"
|
||||
}
|
38
Zend/tests/type_declarations/typed_properties_089.phpt
Normal file
38
Zend/tests/type_declarations/typed_properties_089.phpt
Normal file
@ -0,0 +1,38 @@
|
||||
--TEST--
|
||||
Modification of typed property during assignment must not leak
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public string $prop = "";
|
||||
}
|
||||
|
||||
class B {
|
||||
public function __toString() {
|
||||
global $a;
|
||||
$a->prop = "dont ";
|
||||
$a->prop .= "leak ";
|
||||
$a->prop .= "me!";
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
|
||||
$a = new A;
|
||||
$a->prop = new B;
|
||||
var_dump($a);
|
||||
|
||||
$a = new A;
|
||||
$prop = &$a->prop;
|
||||
$a->prop = new B;
|
||||
var_dump($a);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
object(A)#1 (1) {
|
||||
["prop"]=>
|
||||
string(4) "test"
|
||||
}
|
||||
object(A)#%d (1) {
|
||||
["prop"]=>
|
||||
&string(4) "test"
|
||||
}
|
25
Zend/tests/type_declarations/typed_properties_090.phpt
Normal file
25
Zend/tests/type_declarations/typed_properties_090.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Unsetting typed properties containing a reference must respect shadowing
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
private int $prop = 42;
|
||||
|
||||
public function test() {
|
||||
$x =& $this->prop;
|
||||
unset($this->prop);
|
||||
$x = "foo";
|
||||
var_dump($x);
|
||||
}
|
||||
}
|
||||
class B extends A {
|
||||
private $prop;
|
||||
}
|
||||
|
||||
$b = new B;
|
||||
$b->test();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
string(3) "foo"
|
199
Zend/tests/type_declarations/typed_properties_091.phpt
Normal file
199
Zend/tests/type_declarations/typed_properties_091.phpt
Normal file
@ -0,0 +1,199 @@
|
||||
--TEST--
|
||||
Automatic promotion of falsy to object
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public ?Test $prop;
|
||||
public ?stdClass $stdProp;
|
||||
public ?object $objectProp;
|
||||
|
||||
public static ?Test $staticProp = null;
|
||||
public static ?stdClass $staticStdProp = null;
|
||||
public static ?object $staticObjectProp = null;
|
||||
}
|
||||
|
||||
// Object properties
|
||||
$test = new Test;
|
||||
try {
|
||||
$test->prop->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$test->stdProp->wat = 123;
|
||||
$test->objectProp->wat = 123;
|
||||
var_dump($test);
|
||||
|
||||
// Object properties via reference
|
||||
$test = new Test;
|
||||
$prop =& $test->prop;
|
||||
$stdProp =& $test->stdProp;
|
||||
$objectProp =& $test->objectProp;
|
||||
try {
|
||||
$prop->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$stdProp->wat = 123;
|
||||
$objectProp->wat = 123;
|
||||
var_dump($test);
|
||||
|
||||
// Object properties via reference rw
|
||||
$test = new Test;
|
||||
$prop =& $test->prop;
|
||||
$stdProp =& $test->stdProp;
|
||||
$objectProp =& $test->objectProp;
|
||||
try {
|
||||
$prop->wat->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$stdProp->wat->wat = 123;
|
||||
$objectProp->wat->wat = 123;
|
||||
var_dump($test);
|
||||
|
||||
// Static properties
|
||||
try {
|
||||
Test::$staticProp->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
Test::$staticStdProp->wat = 123;
|
||||
Test::$staticObjectProp->wat = 123;
|
||||
var_dump(Test::$staticProp, Test::$staticStdProp, Test::$staticObjectProp);
|
||||
|
||||
// Non-string property name
|
||||
$test = new Test;
|
||||
$propName = new class {
|
||||
public function __toString() {
|
||||
return 'prop';
|
||||
}
|
||||
};
|
||||
try {
|
||||
$test->$propName->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test);
|
||||
|
||||
// Initially null
|
||||
$test = new Test;
|
||||
$test->prop = NULL;
|
||||
$test->stdProp = NULL;
|
||||
$test->objectProp = NULL;
|
||||
try {
|
||||
$test->prop->wat = 123;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$test->stdProp->wat = 123;
|
||||
$test->objectProp->wat = 123;
|
||||
var_dump($test);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Cannot auto-initialize an stdClass inside property Test::$prop of type ?Test
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
object(Test)#1 (2) {
|
||||
["prop"]=>
|
||||
uninitialized(?Test)
|
||||
["stdProp"]=>
|
||||
object(stdClass)#3 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
["objectProp"]=>
|
||||
object(stdClass)#4 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
}
|
||||
Cannot auto-initialize an stdClass inside a reference held by property Test::$prop of type ?Test
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
object(Test)#5 (3) {
|
||||
["prop"]=>
|
||||
&NULL
|
||||
["stdProp"]=>
|
||||
&object(stdClass)#2 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
["objectProp"]=>
|
||||
&object(stdClass)#4 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
}
|
||||
Cannot auto-initialize an stdClass inside a reference held by property Test::$prop of type ?Test
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
object(Test)#3 (3) {
|
||||
["prop"]=>
|
||||
&NULL
|
||||
["stdProp"]=>
|
||||
&object(stdClass)#1 (1) {
|
||||
["wat"]=>
|
||||
object(stdClass)#2 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
}
|
||||
["objectProp"]=>
|
||||
&object(stdClass)#5 (1) {
|
||||
["wat"]=>
|
||||
object(stdClass)#6 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
}
|
||||
}
|
||||
Cannot auto-initialize an stdClass inside property Test::$staticProp of type ?Test
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
NULL
|
||||
object(stdClass)#4 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
object(stdClass)#8 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
Cannot auto-initialize an stdClass inside property Test::$prop of type ?Test
|
||||
object(Test)#9 (0) {
|
||||
["prop"]=>
|
||||
uninitialized(?Test)
|
||||
["stdProp"]=>
|
||||
uninitialized(?stdClass)
|
||||
["objectProp"]=>
|
||||
uninitialized(?object)
|
||||
}
|
||||
Cannot auto-initialize an stdClass inside property Test::$prop of type ?Test
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
|
||||
Warning: Creating default object from empty value in %s on line %d
|
||||
object(Test)#7 (3) {
|
||||
["prop"]=>
|
||||
NULL
|
||||
["stdProp"]=>
|
||||
object(stdClass)#10 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
["objectProp"]=>
|
||||
object(stdClass)#11 (1) {
|
||||
["wat"]=>
|
||||
int(123)
|
||||
}
|
||||
}
|
41
Zend/tests/type_declarations/typed_properties_092.phpt
Normal file
41
Zend/tests/type_declarations/typed_properties_092.phpt
Normal file
@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
Refs on ASSIGN_OBJ fast-path
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function &ref(&$foo) {
|
||||
return $foo;
|
||||
}
|
||||
|
||||
class Test {
|
||||
public array $prop;
|
||||
public int $prop2;
|
||||
|
||||
public function foo() {
|
||||
$array = [];
|
||||
$ref =& $array;
|
||||
$this->prop = $array;
|
||||
}
|
||||
|
||||
public function bar() {
|
||||
$str = "123";
|
||||
$this->prop2 = ref($str);
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
$test->foo();
|
||||
$test->foo();
|
||||
$test->bar();
|
||||
$test->bar();
|
||||
var_dump($test);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
object(Test)#1 (2) {
|
||||
["prop"]=>
|
||||
array(0) {
|
||||
}
|
||||
["prop2"]=>
|
||||
int(123)
|
||||
}
|
31
Zend/tests/type_declarations/typed_properties_093.phpt
Normal file
31
Zend/tests/type_declarations/typed_properties_093.phpt
Normal file
@ -0,0 +1,31 @@
|
||||
--TEST--
|
||||
Typed property assignment by ref with variable name
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public int $prop;
|
||||
}
|
||||
|
||||
$name = new class {
|
||||
public function __toString() {
|
||||
return 'prop';
|
||||
}
|
||||
};
|
||||
|
||||
$test = new Test;
|
||||
$ref = "foobar";
|
||||
try {
|
||||
$test->$name =& $ref;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property Test::$prop must be int, string used
|
||||
object(Test)#2 (0) {
|
||||
["prop"]=>
|
||||
uninitialized(int)
|
||||
}
|
36
Zend/tests/type_declarations/typed_properties_094.phpt
Normal file
36
Zend/tests/type_declarations/typed_properties_094.phpt
Normal file
@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
Edge cases relating to reference source tracking
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public int $prop = 42;
|
||||
}
|
||||
class B extends A {
|
||||
}
|
||||
|
||||
$b = new B;
|
||||
$r =& $b->prop;
|
||||
unset($b);
|
||||
$r = "foo"; // ok
|
||||
|
||||
class A2 {
|
||||
private int $prop = 42;
|
||||
|
||||
public function &getRef() {
|
||||
return $this->prop;
|
||||
}
|
||||
}
|
||||
class B2 extends A2 {
|
||||
public $prop;
|
||||
}
|
||||
|
||||
$b2 = new B2;
|
||||
$r2 =& $b2->getRef();
|
||||
unset($b2);
|
||||
$r2 = "foo"; // ok
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECT--
|
||||
===DONE===
|
84
Zend/tests/type_declarations/typed_properties_095.phpt
Normal file
84
Zend/tests/type_declarations/typed_properties_095.phpt
Normal file
@ -0,0 +1,84 @@
|
||||
--TEST--
|
||||
Typed properties in internal classes
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('zend-test')) die('skip requires zend-test'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// Internal typed properties
|
||||
|
||||
$obj = new _ZendTestClass;
|
||||
var_dump($obj->intProp);
|
||||
try {
|
||||
$obj->intProp = "foobar";
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$obj->intProp = 456;
|
||||
|
||||
try {
|
||||
$obj->classProp = $obj;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$obj->classProp = new stdClass;
|
||||
var_dump($obj);
|
||||
|
||||
// Inherit from internal class
|
||||
|
||||
class Test extends _ZendTestClass {
|
||||
}
|
||||
|
||||
$obj = new Test;
|
||||
var_dump($obj->intProp);
|
||||
try {
|
||||
$obj->intProp = "foobar";
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$obj->intProp = 456;
|
||||
|
||||
try {
|
||||
$obj->classProp = $obj;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
$obj->classProp = new stdClass;
|
||||
var_dump($obj);
|
||||
|
||||
// Static internal typed properties
|
||||
|
||||
var_dump(_ZendTestClass::$staticIntProp);
|
||||
try {
|
||||
_ZendTestClass::$staticIntProp = "foobar";
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
_ZendTestClass::$staticIntProp = 456;
|
||||
var_dump(_ZendTestClass::$staticIntProp);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(123)
|
||||
Typed property _ZendTestClass::$intProp must be int, string used
|
||||
Typed property _ZendTestClass::$classProp must be an instance of stdClass or null, _ZendTestClass used
|
||||
object(_ZendTestClass)#1 (2) {
|
||||
["intProp"]=>
|
||||
int(456)
|
||||
["classProp"]=>
|
||||
object(stdClass)#2 (0) {
|
||||
}
|
||||
}
|
||||
int(123)
|
||||
Typed property _ZendTestClass::$intProp must be int, string used
|
||||
Typed property _ZendTestClass::$classProp must be an instance of stdClass or null, Test used
|
||||
object(Test)#4 (2) {
|
||||
["intProp"]=>
|
||||
int(456)
|
||||
["classProp"]=>
|
||||
object(stdClass)#1 (0) {
|
||||
}
|
||||
}
|
||||
int(123)
|
||||
Typed property _ZendTestClass::$staticIntProp must be int, string used
|
||||
int(456)
|
46
Zend/tests/type_declarations/typed_properties_096.phpt
Normal file
46
Zend/tests/type_declarations/typed_properties_096.phpt
Normal file
@ -0,0 +1,46 @@
|
||||
--TEST--
|
||||
References to typed properties with undefined classes
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test1 {
|
||||
public Foobar $prop;
|
||||
public int $prop2;
|
||||
}
|
||||
|
||||
$test = new Test1;
|
||||
$test->prop2 = 123;
|
||||
$ref =& $test->prop2;
|
||||
try {
|
||||
$test->prop =& $ref;
|
||||
} catch (Error $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test);
|
||||
|
||||
class Test2 {
|
||||
public ?Foobar $prop;
|
||||
public ?int $prop2;
|
||||
}
|
||||
|
||||
$test = new Test2;
|
||||
$test->prop2 = null;
|
||||
$ref =& $test->prop2;
|
||||
$test->prop =& $ref;
|
||||
var_dump($test);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Typed property Test1::$prop must be an instance of Foobar, int used
|
||||
object(Test1)#1 (1) {
|
||||
["prop"]=>
|
||||
uninitialized(Foobar)
|
||||
["prop2"]=>
|
||||
&int(123)
|
||||
}
|
||||
object(Test2)#3 (2) {
|
||||
["prop"]=>
|
||||
&NULL
|
||||
["prop2"]=>
|
||||
&NULL
|
||||
}
|
90
Zend/tests/type_declarations/typed_properties_097.phpt
Normal file
90
Zend/tests/type_declarations/typed_properties_097.phpt
Normal file
@ -0,0 +1,90 @@
|
||||
--TEST--
|
||||
Incrementing/decrementing past max/min value (additional cases)
|
||||
--SKIPIF--
|
||||
<?php if (PHP_INT_SIZE != 8) die('skip 64 bit test'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public int $foo;
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
|
||||
$test->foo = PHP_INT_MIN;
|
||||
try {
|
||||
--$test->foo;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
try {
|
||||
$test->foo--;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
|
||||
$test->foo = PHP_INT_MAX;
|
||||
try {
|
||||
++$test->foo;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
try {
|
||||
$test->foo++;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
|
||||
// Do the same things again, but with the property being a reference.
|
||||
$ref =& $test->foo;
|
||||
|
||||
$test->foo = PHP_INT_MIN;
|
||||
try {
|
||||
--$test->foo;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
try {
|
||||
$test->foo--;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
|
||||
$test->foo = PHP_INT_MAX;
|
||||
try {
|
||||
++$test->foo;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
try {
|
||||
$test->foo++;
|
||||
} catch (TypeError $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
var_dump($test->foo);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot decrement property Test::$foo of type int past its minimal value
|
||||
int(-9223372036854775808)
|
||||
Cannot decrement property Test::$foo of type int past its minimal value
|
||||
int(-9223372036854775808)
|
||||
Cannot increment property Test::$foo of type int past its maximal value
|
||||
int(9223372036854775807)
|
||||
Cannot increment property Test::$foo of type int past its maximal value
|
||||
int(9223372036854775807)
|
||||
Cannot decrement property Test::$foo of type int past its minimal value
|
||||
int(-9223372036854775808)
|
||||
Cannot decrement property Test::$foo of type int past its minimal value
|
||||
int(-9223372036854775808)
|
||||
Cannot increment property Test::$foo of type int past its maximal value
|
||||
int(9223372036854775807)
|
||||
Cannot increment property Test::$foo of type int past its maximal value
|
||||
int(9223372036854775807)
|
17
Zend/tests/type_declarations/typed_properties_098.phpt
Normal file
17
Zend/tests/type_declarations/typed_properties_098.phpt
Normal file
@ -0,0 +1,17 @@
|
||||
--TEST--
|
||||
Make sure uninitialized property is initialized to null when taken by reference
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public $prop;
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
unset($test->prop);
|
||||
$ref =& $test->prop;
|
||||
var_dump($ref);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
NULL
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user