Skip to content

Implement typed properties #3734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 56 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
46fbe12
Implement typed properties
nikic Jan 7, 2019
973f8c5
Remove redundant trailing newlines from tests
nikic Jan 7, 2019
784aebe
Coding style tweaks
nikic Jan 7, 2019
ac6b431
Add test for typed properties on internal class
nikic Jan 7, 2019
d95f131
Code cleanup
nikic Jan 7, 2019
0395fe5
Avoid direct uses of zend_try_assign API
nikic Jan 7, 2019
37b3de6
Remove alloc_polymorphic_cache_slots API
nikic Jan 7, 2019
5e009e7
Rename get_mangled_property_name to get_unmangled_property_name
nikic Jan 7, 2019
9e82c5a
Cleanup code and add more trait + self tests
nikic Jan 7, 2019
be0cfbb
Restore exception
nikic Jan 8, 2019
9c55d73
Remove requirement that reference sources must have resolved types
nikic Jan 8, 2019
23bb53f
Tweak assign_to_variable
nikic Jan 8, 2019
b4f5e11
Remove dubious expectations
nikic Jan 8, 2019
f1d9f22
Move error generation into verify_property_type
nikic Jan 8, 2019
117d1da
Code cleanup
nikic Jan 8, 2019
3923574
Check for incdec overflow if no refs are involved
nikic Jan 8, 2019
be63cc1
Prefer showing a property type error over a reference error
nikic Jan 8, 2019
1282365
Extract error code into cold function
nikic Jan 8, 2019
ee84e01
Code cleanup
nikic Jan 8, 2019
bc27695
Fix handling of null vs undef in auto-vivification
nikic Jan 8, 2019
ba09a1d
Fix hardcoded paths in tests
nikic Jan 9, 2019
4e34d90
Cleanup
nikic Jan 9, 2019
dcefc11
More changes to initialization handling
nikic Jan 9, 2019
6cc4f84
Inherit the HAS_TYPE_HINTS flag
nikic Jan 9, 2019
3ae6f61
Set HAS_TYPE_HINTS for static props as well
nikic Jan 9, 2019
e9ee417
Reuse object flag code for static props
nikic Jan 9, 2019
07b95d5
Move TODO comment
nikic Jan 9, 2019
c6bd1d9
In debug mode, we want to make sure that refs do have type sources
nikic Jan 9, 2019
f103983
Compile by-ref foreach with the by_ref flag
nikic Jan 9, 2019
9fdb55d
Fix handling of private properties in foreach
nikic Jan 9, 2019
0245c68
Exit early for strict_types in verify_type_assignable_zval
nikic Jan 9, 2019
9f2734a
Code cleanup
nikic Jan 9, 2019
a427595
Remove dependence on zend_resolve_property_type
nikic Jan 9, 2019
1327829
Fix ref assignable with strict types
nikic Jan 9, 2019
22dfc44
Only use information from visible properties in opcache
nikic Jan 9, 2019
90cfd7a
Make sure fetch_property_type_info is only used with valid offset
nikic Jan 9, 2019
dcc8ea8
write_property value may not be REF
nikic Jan 9, 2019
cfd76b0
Use faster API too look up property info in object handlers
nikic Jan 10, 2019
efbcbd6
Fix dumping of private uninitialized props
nikic Jan 10, 2019
bb3e82b
Move everything over to the slot API
nikic Jan 10, 2019
1005f92
Use slot API during cloning
nikic Jan 10, 2019
88d966b
Remove bogus DEREF
nikic Jan 10, 2019
8b1a6a3
Remove unnecessary SEPARATE
nikic Jan 10, 2019
d1ac734
Prefer checking type prior to modification
nikic Jan 10, 2019
dc68354
Fix ref post incdec without type sources
nikic Jan 10, 2019
d7dbf11
Remove manual ref sources initialization
nikic Jan 10, 2019
223cd77
Property dump DIM_WRITE/OBJ_WRITE flags
nikic Jan 10, 2019
5b7a5b0
Remove bogus PARAM_ZVAL_DEREF
nikic Jan 10, 2019
df34631
Convert checks to assertions
nikic Jan 10, 2019
fa59a56
Use slot API in unserialization
nikic Jan 10, 2019
26139a4
Fetch class types in property hints in opcache
nikic Jan 10, 2019
4eec659
Move ASSIGN_OBJ_REF to the right place
nikic Jan 10, 2019
e6510a5
Support typed properties in opcache file cache
nikic Jan 10, 2019
8264d27
Also handle CE types in persistence
nikic Jan 10, 2019
6150ddd
Add UPGRADING entry
nikic Jan 10, 2019
7e7b446
Add UPGRADING.INTERNALS notes
nikic Jan 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,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
Expand Down
13 changes: 13 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
========================
Expand Down
44 changes: 44 additions & 0 deletions Zend/tests/type_declarations/typed_properties_001.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions Zend/tests/type_declarations/typed_properties_002.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions Zend/tests/type_declarations/typed_properties_003.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions Zend/tests/type_declarations/typed_properties_004.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions Zend/tests/type_declarations/typed_properties_005.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions Zend/tests/type_declarations/typed_properties_006.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions Zend/tests/type_declarations/typed_properties_007.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions Zend/tests/type_declarations/typed_properties_008.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 23 additions & 0 deletions Zend/tests/type_declarations/typed_properties_009.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions Zend/tests/type_declarations/typed_properties_010.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions Zend/tests/type_declarations/typed_properties_011.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions Zend/tests/type_declarations/typed_properties_012.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions Zend/tests/type_declarations/typed_properties_013.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions Zend/tests/type_declarations/typed_properties_014.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions Zend/tests/type_declarations/typed_properties_015.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions Zend/tests/type_declarations/typed_properties_016.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions Zend/tests/type_declarations/typed_properties_017.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions Zend/tests/type_declarations/typed_properties_018.phpt
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions Zend/tests/type_declarations/typed_properties_019.phpt
Original file line number Diff line number Diff line change
@@ -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
Loading