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_specializationwas removed and its behavior is now enabled by default. This change disables the implicit interoperability betweenvarrays anddarrays. Instead,array(soon to be removed),varrayanddarrayare now treated as types in their own right. Specifically:- Using a
varraywhere adarrayis expected (at parameter and return value typehints) throws, and vice versa. The same goes for property typehints, if they are checked at runtime. varrays now maintain a “vec-like” layout, with integer keys from 0 to (size - 1). Attempting to set a string key in avarraythrows, as does attempting to unset any element other than the last one.- Tuples and shapes are internally represented as
varrays anddarrays, respectively. As a result,darray is tuple(...)returnsfalseanddarray as tuple(...)throws. The same goes forvarray is shape(...)andvarray as shape(...). - Comparing a
varrayand adarrayusing==or===always returnsfalse. - Comparing a
darraywith avarray, or twodarrays using>,<,<=,>=,<>,<=>results in an exception. Twovarrays can still be compared. - If property type enforcement is turned on, property type invariance rules
for class hierarchies will apply to
varray,darrayandarray. 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_noticeshhvm.hack_arr_compat_check_varray_promotehhvm.hack_arr_compat_check_implicit_varray_appendhhvm.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 fromsyntax 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.