[PHP-DEV] [RFC] [Vote] Type Guards for Classes

Introduction


This RFC proposes a new feature in PHP: type guards for classes (or interfaces). This feature aims to simplify and standardize the process of verifying that a variable is an instance of a specific class, enhancing code readability and reducing boilerplate code.

Motivation


Currently, in PHP, to ensure that a variable is an instance of a specific class, developers need to use the instanceof operator and manually throw an exception if the check fails. This results in repetitive boilerplate code scattered throughout the codebase. A new syntax, (ClassName) $variable, is proposed to streamline this process by performing an instanceof check and throwing a TypeError if the variable is not an instance of the specified class.

Proposal


Introduce a new type guard syntax for classes:

(Foo) $variable;

This syntax will internally perform the following operations:

  1. Check if $variable is an instance of Foo.
  2. If the check fails, throw a TypeError with a message indicating the expected and actual types.

Example:
Consider the following class definition:

class Foo {
// class definition
}

To ensure a variable is an instance of Foo, instead of writing:

if (!$variable instanceof Foo) {
throw new TypeError('Expected instance of Foo, got ' . gettype($variable));
}

Developers can use the new type guard syntax:

(Foo) $variable;

Backward Compatibility


This feature introduces new syntax and does not affect existing code. It is fully backward-compatible, as it does not modify or deprecate any existing functionality.

On Thu, 16 May 2024 at 22:33, Patrik Václavek <PaTrOnY@email.cz> wrote:

Introduction


This RFC proposes a new feature in PHP: type guards for classes (or interfaces). This feature aims to simplify and standardize the process of verifying that a variable is an instance of a specific class, enhancing code readability and reducing boilerplate code.

Hi, please see this discussion:
https://externals.io/message/105332

In particular this comment from Nikita:
https://externals.io/message/105332#105348

That being said, I would still love it if we could find a way to get this feature, under this syntax or another, into PHP!

  • Ben

Hi Patrik

On Thu, May 16, 2024 at 10:31 PM Patrik Václavek <PaTrOnY@email.cz> wrote:

Introduce a new type guard syntax for classes:

(Foo) $variable;

This syntax will internally perform the following operations:

1. Check if `$variable` is an instance of `Foo`.
2. If the check fails, throw a `TypeError` with a message indicating the expected and actual types.

Note that this feature is covered under the pattern matching RFC with
the "Throwing alternative" extension.
https://wiki.php.net/rfc/pattern-matching#throwing_alternative

In addition to just class types, it would support all other patterns,
including scalar types, union types, array shapes, etc.

Ilija

On Thu, May 16, 2024, at 3:31 PM, Patrik Václavek wrote:

Introduction
*************

This RFC proposes a new feature in PHP: type guards for classes (or
interfaces). This feature aims to simplify and standardize the process
of verifying that a variable is an instance of a specific class,
enhancing code readability and reducing boilerplate code.

Without commenting on the idea itself, this is just a proposal at the moment. The subject line implies there's a formal RFC now up for a vote, when there is not even a formal RFC yet. Ie, please don't abuse the subject line incorrectly. :slight_smile:

To comment on the idea itself, I believe Ilija is correct that using pattern matching would be the better approach here. Right now the RFC suggests $foo as <pattern> would return true or throw, but "return $foo or throw" would indeed make more sense. And then give us the entire power of pattern matching. (That RFC will come up formally soon(tm), I swear.)

--Larry Garfield

On Thu, May 16, 2024 at 1:32 PM Patrik Václavek <PaTrOnY@email.cz> wrote:

Introduction


This RFC proposes a new feature in PHP: type guards for classes (or interfaces). This feature aims to simplify and standardize the process of verifying that a variable is an instance of a specific class, enhancing code readability and reducing boilerplate code.

Motivation


Currently, in PHP, to ensure that a variable is an instance of a specific class, developers need to use the instanceof operator and manually throw an exception if the check fails. This results in repetitive boilerplate code scattered throughout the codebase. A new syntax, (ClassName) $variable, is proposed to streamline this process by performing an instanceof check and throwing a TypeError if the variable is not an instance of the specified class.

Proposal


Introduce a new type guard syntax for classes:

(Foo) $variable;

This syntax will internally perform the following operations:

  1. Check if $variable is an instance of Foo.
  2. If the check fails, throw a TypeError with a message indicating the expected and actual types.

Example:
Consider the following class definition:

class Foo {
// class definition
}

To ensure a variable is an instance of Foo, instead of writing:

if (!$variable instanceof Foo) {
throw new TypeError('Expected instance of Foo, got ' . gettype($variable));
}

Developers can use the new type guard syntax:

(Foo) $variable;

Backward Compatibility


This feature introduces new syntax and does not affect existing code. It is fully backward-compatible, as it does not modify or deprecate any existing functionality.

Since this throws, I’m struggling to understand how this would replace any usages of instanceof other than if (!($var instanceof Foo)) throw new TypeError();

Also, this is not an RFC with a page I can look at OR something in a vote, so the subject line is a bit of a lie.

But now that I’ve gotten my grumps out of the way, better class specific syntax is in general something that I think is positive and worth exploring.

Jordan

On Thu, May 16, 2024, at 22:31, Patrik Václavek wrote:

This feature aims to simplify and standardize the process of verifying that a variable is an instance of a specific class, enhancing code readability and reducing boilerplate code.

Currently, in PHP, to ensure that a variable is an instance of a specific class, developers need to use the instanceof operator and manually throw an exception if the check fails. This results in repetitive boilerplate code scattered throughout the codebase. A new syntax, (ClassName) $variable, is proposed to streamline this process by performing an instanceof check and throwing a TypeError if the variable is not an instance of the specified class.

I view variables changing types to be an anti-pattern.

Instead if adding type guards, I would rather see this problem solved by having typed local variables. This ensures that a variable always holds a specific type, avoiding the need of repetitive scattered type guards. Working with variables would then be the same as working with class properties. They could be typed or untyped.

Also, I see the need for type guards as a symptom of bad composition. Mostly methods that are too large would benefit. If a method is decomposed into smaller methods the use of parameter and return type checks it’s unlikely there is need for additional type guards.