PHP's Type Handling
Agenda
-
PHP's Type System
-
Type Coercion
-
Weak vs. Strict Mode
-
Argument/Return/Property Validation
-
Inheritance Compability Validation
PHP's Type System
-
Basic types:
- null, bool, int, float, string, array, resource, object
-
Additional type declarations:
- PHP <8.0: callable, iterable, void
- PHP 8.0: static, mixed (top type), false
- PHP 8.1: never (bottom type)
-
Union types:
- https://wiki.php.net/rfc/union_types_v2
-
Intersection types:
- https://wiki.php.net/rfc/pure-intersection-types
Type Coercion
-
The process and rules of converting types to each other
-
Affects parameter/return/property type validation, operators, array keys
Type Coercion
-
PHP historically had very weird numeric string handling: https://3v4l.org/QAumr
-
This was improved as of PHP 8.0
-
https://wiki.php.net/rfc/string_to_number_comparison
-
https://wiki.php.net/rfc/saner-numeric-strings
-
Type Coercion
-
Implicit float to int conversion can lose precision: https://3v4l.org/rRvHS
-
This is going to be improved as of PHP 8.1
-
https://wiki.php.net/rfc/implicit-float-int-deprecate
-
Type Coercion
-
Array keys have their own coercion rules:
- null -> ""
- numeric string -> int
- float -> int
- string -> string
Weak vs. Strict Mode
-
Introduced with scalar types in PHP 7.0
-
Mode can be set per file via a directive
-
declare(strict_types=1)
-
Only affects param, return, property types
-
Only affects calls within the file
-
Internal functions do not always respect it
- PHP 8.0+: only a few dozen of such cases
- PHP 7.x: lots of cases
Weak vs. Strict Mode
-
Weak mode supports type coercion:
- bool -> int/float/string
- numeric string -> bool/int/float
- non-numeric string -> bool
- Stringable -> string
- examples: https://3v4l.org/lSGSr
Weak vs. Strict Mode
-
Strict mode doesn't support type coercion:
- with the exception of int to float (non-widening) conversion
- examples: https://3v4l.org/8U8FY
Param Type Validation
-
Run-time validation only
-
Invalid parameter type declarations:
-
resource, static, void
-
-
Parameters are non-nullable by default
- except for internal functions: https://wiki.php.net/rfc/deprecate_null_to_scalar_internal_arg
-
Null default value implicitly converts a non-nullable parameter to nullable
-
int $a = null -> ?int $a = null
-
Param Type Validation
-
User-land type errors:
-
Always a TypeError is thrown
-
-
Internal type errors:
- PHP <8.0:
- weak mode: usually a warning + false/null return
- strict mode: TypeError
- PHP 8.0+:
- always a TypeError
- PHP <8.0:
Return Type Validation
-
Mainly run-time validation
- void is validated at compile type
-
Even void functions return null implicitly
-
Invalid return type declarations:
-
resource
-
-
PHP performs optimizations based on return type
- zend_func_info.c stores additional type information
Property Type Validation
-
Added in PHP 7.4
-
Implicit property default values:
- untyped properties: null
- typed properties: uninitialized state
-
Unavailable type declarations:
- void
- callable
- resource
- static
-
Weak vs strict mode:
- user-land typed properties always respect it
- PHP 8.1 is going to make almost all internal properties typed
Inheritance Compability
-
What is LSP?
-
Variance categories:
- invariant (properties)
- covariant (return types)
- contravariant (param types)
Inheritance Compability
-
Validated at compile-time:
-
type compability
-
number of params
-
required/optional/variadic params
-
param default values
-
param names are not (yet) in the contract
-
visibility
-
-
PHP had a long way to support variance:
- PHP 7.2: https://wiki.php.net/rfc/parameter-no-type-variance
- PHP 7.4: https://wiki.php.net/rfc/covariant-returns-and-contravariant-parameters
Inheritance Compability
-
Until PHP 8.1, internal methods usually didn't have a return type declaration
- https://wiki.php.net/rfc/internal_method_return_types
-
Until PHP 8.1, class constants were overridable
- https://wiki.php.net/rfc/final_class_const
PHP's Type Handling
By Máté Kocsis
PHP's Type Handling
- 429