HHVM 4.45 is released! This release marks the end of support for 4.38 and 4.39 (some versions were supported for longer than usual because 4.37 was skipped); HHVM 4.40–4.44 remain supported, as do the 4.8 and 4.32 LTS releases.


  • Fixed the type refinement done by is_array($value) to be less restrictive. The type-checker now understands the refined type to be the intersection of $value’s original type and varray_or_darray, instead of always rewriting the type to varray_or_darray.
    • For example, after passing a darray value to is_array, the type-checker no longer rewrites $value’s type to varray_or_darray but keeps treating it as a darray.
  • New built-in functions HH\autoload_type_to_path(), HH\autoload_function_to_path() and HH\autoload_constant_to_path() can be used to look up entries in the autoload map (e.g. for debugging).
  • hh_client --type-at-pos now returns additional information about how the type was determined.
  • Various small clarifications in type-checker error messages (e.g. “missing property” instead of “missing member”).

Breaking Changes

  • Empty switch statements are no longer allowed. They now produce a type-checker error as well as a fatal error at runtime, and in the future will be treated as a parsing error.
  • The type-checker now raises an error for any lambda functions whose types cannot be inferred. This can reveal previously hidden type errors.
    • In previous HHVM versions, the new_inference_lambda=true option in .hhconfig enables this behavior.
  • array_key_exists() now throws an InvalidArgumentException if the provided key is null.
    • In HHVM 4.44, the hhvm.hack_arr_compat_check_null_hack_array_key=true and hhvm.hack_arr_compat_notices=true INI options can be used to raise a notice.
  • The ArrayAccess interface no longer provides its “magic” behavior. The interface still exists but its methods now need to be called directly (e.g. $stack->push(42) instead of $stack[] = 42;).
  • When attempting to override a final method, the type-checker now raises an error in the child class instead of the parent class. This doesn’t introduce any new errors but may require some HH_FIXMEs to be moved.
    • The same change was made for class properties declared with <<__Const>> or <<__LateInit>>.
  • Using a type constant via this as a reified generic type parameter in a type annotation (e.g. ClassWithReifiedGeneric<this::T> $arg) is now a type-checker error.
    • It is still allowed in function calls (foo<this::T>()) including constructor calls (new ClassWithReifiedGeneric<this::T>()).
  • We no longer build packages for Ubuntu 18.10 (its official support ended in July 2019).

Future Changes

  • array() literals will be removed; use vec/dict/keyset instead if possible, otherwise varray or darray.
    • Automated migration is available in HHAST 4.33.6: hhast-migrate --php-arrays
  • The runtime will be changed to throw an exception for any switch statements where none of the cases matched the provided value.
    • A default branch should be added to any switch statements that intentionally don’t cover all possible cases.
    • Use the hhvm.throw_on_non_exhaustive_switch=2 INI option to enable this behavior now (or set the value to 1 to raise a warning instead of throwing an exception).
  • Upper bounds on generic type parameters will be enforced at runtime. For example, passing true to a function declared as function takes_arraykey<T as arraykey>(T $arg) will be a runtime error in the future.
    • Any such violations already raise type-checker errors, but this could reveal new errors in code without full type coverage.
    • It is enforced regardless of where the generic parameter appears (function parameter and return types, class properties, etc).
    • Use the INI options hhvm.emit_generics_ub=true with hhvm.enforce_generics_ub=2 to enable this behavior now (or set the latter value to 1 to raise a warning instead of a fatal error).
  • The behavior of is_array() will likely be changed to also return true for Hack arrays (vec, dict and keyset).
    • Currently it only returns true for legacy arrays (array, varray and darray). This change should make it easier to migrate from legacy arrays to Hack arrays.
    • New built-in function HH\is_php_array() was added in this release, which only returns true for legacy arrays (the current behavior of is_array()). You can replace any calls to is_array() with this function to guarantee no behavior changes in the future.
    • You can use HH\is_any_array() to preemptively migrate any is_array() calls to the future behavior.
  • Comparing Hack arrays (vec, dict and keyset) with boolean values using the “fuzzy” comparison operators == and != will be changed to consider empty arrays equal to false and non-empty arrays to true.
    • This is consistent with how fuzzy comparisons work for other types, including legacy arrays (array, varray, darray). It should make it easier to migrate from legacy arrays to Hack arrays.
    • Strict equality operators === and !== are not affected, they will always evaluate to false when comparing values of different types. It is highly recommended to use these strict operators for comparisons and use C\is_empty() for checking the emptiness of arrays instead.
    • Use the hhvm.hack_arr_compat_hack_arr_cmp_notices=1 INI option to raise a notice whenever Hack arrays are compared with boolean values, and therefore the result may be affected by this future change.