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:

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

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

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