Smart Cast¶
A smart cast, also called compiler-enforced type narrowing, is a feature where the compiler automatically refines the static type of a variable inside a branch, based on a preceding type-check, without requiring the programmer to insert an explicit cast expression.
In Kotlin, after if (x is String) the compiler knows that x is a String inside that branch, and all String methods become available without casting. In TypeScript, a type guard such as typeof x === 'string' narrows x from string | number to string in the truthy branch. In both cases the narrowing is enforced by the compiler or type-checker: code that tries to use the variable as a different type is a compile-time error.
PHP does not support smart casts. PHP’s type system is verified at runtime, not compile time. Within an instanceof or is_string() branch, PHP will call the correct methods, but:
There is no compile-time enforcement: the type-checker integrated into IDEs (PHPStan, Psalm, Rector) can simulate narrowing, but the PHP engine itself makes no such guarantee.
The programmer may still write code that uses the variable as a different type, and PHP will only raise an error (or silently coerce) at runtime.
PHP does not have union-type narrowing built into the runtime in the sense that Kotlin’s compiler tracks flow.
Static analysis tools (PHPStan level 8, Psalm --strict-mode) approximate smart-cast behaviour through flow-sensitive type inference, but this is a tool-level feature, not a language-engine feature.
<?php
// PHP runtime checks — no compiler-enforced narrowing.
function process(int|string $value): string {
if (is_string($value)) {
// PHPStan / Psalm will narrow $value to string here,
// but the PHP engine itself does not enforce this at compile time.
return strtoupper($value);
}
// $value is int here — again, tools narrow, not the engine.
return (string) ($value * 2);
}
// instanceof narrows for IDEs and static analysers, not for the runtime.
function describe(object $obj): string {
if ($obj instanceof \DateTimeImmutable) {
// Tools know $obj is DateTimeImmutable; PHP does not enforce it statically.
return $obj->format('Y-m-d');
}
return get_class($obj);
}
?>
See also Kotlin smart casts, TypeScript type narrowing, PHPStan type narrowing and Psalm – Typing in Psalm.
Related : Cast Operator, instanceof, Property Type Declaration, Typed Property