Expressions And Operators: As

At runtime, the as operator evaluates to the left-hand operand if that operand's type matches the type named by the right-hand operand; otherwise, the operator throws a TypeAssertionException. Statically, the operator unconditionally refines the type of the left-hand operand. The as operator also comes in a non-throwing variant ?as, which evaluates to null if the types don't match. For example:

1 as int        // 1
'foo' as int    // TypeAssertionException
1 as num        // 1
1.5 as num      // 1.5
'foo' as num    // TypeAssertionException

For enums, the operator validates that the value is in the given enum.

enum MyEnum: int {
  FOO = 1;
1 as MyEnum       // 1
42 as MyEnum      // TypeAssertionException
'foo' as MyEnum   // TypeAssertionException

For generic types, we must use the _ (wildcard) placeholder for the type parameters.

interface MyInterface<T> {}
$x as dict<_, _>;

For tuples and shapes, the operator validates the size and recursively validates every field in the value.

$x as shape(
  'foo' => int,
  ?'bar' => (int, ?string, MyEnum),
  // ...

For type aliases and type constants, the operators will test the value against the underlying runtime type.

The nonnull type is handled specially; if the left-hand operand of as nonnull is known to be of type ?T, it is refined to T, instead of simply to nonnull.