HHVM 4.64
HHVM 4.64 is released! This release marks the end of support for 4.57; HHVM 4.58–4.62 remain supported (4.63 was skipped), as do the 4.32 and 4.56 LTS releases.
Breaking Changes
- The INI flag
hhvm.hack_arr_compat_specialization
was removed and its behavior is now enabled by default. This change disables the implicit interoperability betweenvarray
s anddarray
s. Instead,array
(soon to be removed),varray
anddarray
are now treated as types in their own right. Specifically:- Using a
varray
where adarray
is expected (at parameter and return value typehints) throws, and vice versa. The same goes for property typehints, if they are checked at runtime. varray
s now maintain a “vec
-like” layout, with integer keys from 0 to (size - 1). Attempting to set a string key in avarray
throws, as does attempting to unset any element other than the last one.- Tuples and shapes are internally represented as
varray
s anddarray
s, respectively. As a result,darray is tuple(...)
returnsfalse
anddarray as tuple(...)
throws. The same goes forvarray is shape(...)
andvarray as shape(...)
. - Comparing a
varray
and adarray
using==
or===
always returnsfalse
. - Comparing a
darray
with avarray
, or twodarray
s using>
,<
,<=
,>=
,<>
,<=>
results in an exception. Twovarray
s can still be compared. - If property type enforcement is turned on, property type invariance rules
for class hierarchies will apply to
varray
,darray
andarray
. For example, a child class will not be able to redeclare a property with typevarray<Tv>
if the parent class’ property is typeddarray<Tk, Tv>
. - Additional related INI flags were removed, since they no longer have any
effect:
hhvm.hack_arr_compat_type_hint_notices
hhvm.hack_arr_compat_check_varray_promote
hhvm.hack_arr_compat_check_implicit_varray_append
hhvm.hack_arr_compat_dv_cmp_notices
- Using a
- Attempting to override a non-abstract constant defined in an interface when implementing or extending that interface is now a typechecker error. It had already been a runtime error.
- The function
HH\global_keys()
was removed. Other methods of enumerating all global variables, such asHH\global_get('GLOBALS')
or$GLOBALS['GLOBALS']
, are also expected to stop working soon.
Future Changes
- We expect
array(...)
literals to be completely removed in the next release. All code will need to be migrated tovarray[...]
anddarray[...]
, or preferablyvec[...]
anddict[...]
(if it can be done safely).- Automated migration is available in HHAST
v4.33.6 or newer:
hhast-migrate --php-arrays
- Automated migration is available in HHAST
v4.33.6 or newer:
- Any remaining methods of enumerating all global variables, such as
HH\global_get('GLOBALS')
or$GLOBALS['GLOBALS']
, are expected to stop working in a future release. - We expect to remove the
yield from
syntax in a future release. In most cases, it can be replaced by other syntax.
Replacing yield from
Here’s a list of replacements to use based on the complexity of the use case:
If only the values, or only (key, value) pairs, are used, replace yield from
with foreach...yield
:
1
2
3
4
5
6
7
8
9
10
11
12
13
function only_values_old($gen) {
yield from $gen;
}
function only_values_new($gen) {
foreach ($gen as $v) { yield $v; }
}
function keys_values_old($gen) {
yield from $gen;
}
function keys_values_new($gen) {
foreach ($gen as $k => $v) { yield $k => $v; }
}
Use getReturn
to evaluate the result of the yield from
expression:
1
2
3
4
5
6
7
8
9
function return_old($gen) {
$x = yield from $gen;
var_dump($x);
}
function return_new($gen) {
foreach ($gen as $v) { yield $v; }
$x = $gen->getReturn();
var_dump($x);
}
Use send
to pass values back into the inner generator (if callers of the
yield from
outer generator do so). This use case is quite rare.
1
2
3
4
5
6
7
8
function send_old($gen) {
yield from $gen;
}
function send_new($gen) {
for ($gen->next(); $gen->valid(); $gen->send($s)) {
$s = yield $gen->key() => $gen->current();
}
}
There’s one behavior of yield from
syntax that can’t be captured easily by
rewrites like the above: if the same generator is aliased by a yield from
and
elsewhere, next()
on that generator will advance the yield from
. Such code
will need a rewrite to make state explicit.