Strategy for handling moved classes does not cover instanceof / typehints

Created on 16 July 2025, about 1 month ago

Problem/Motivation

📌 Add a classloader that can handle class moves Active introduces a strategy for handling moved classes as outlined in https://www.drupal.org/node/3509577

This was used in 📌 Move node forms to proper namespace (Drupal\node\Form) Needs work (11.2) to move the node classes.

As the CR states:

When the old class is autoloaded, the classloader will detect this, and swap it for the new one using class_alias(). When the deprecation-related keys are specified, the classloader will trigger E_USER_DEPRECATED with a message.

What was not discussed in the original issue and has caught some custom and contrib modules out is that using instanceof or type hinting methods / functions does not trigger the autoloader.

E.g as reported in slack by @fjgarlin

use Drupal\node\NodeForm;

...
$isNodeForm = $form_object instanceof NodeForm;
 

This will evaluate to false as instanceof is not triggering the autoloader.

Type hint functions / methods will at least blow up:

function test_form_node_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $form_object = $form_state->getFormObject();
  test_deprecated_autoloader($form_object);
}

function test_deprecated_autoloader(\Drupal\node\NodeForm $form_object) {
  // Oh no.
}

Will result in

TypeError: test_deprecated_autoloader(): Argument #1 ($form_object) must be of type Drupal\node\NodeForm, Drupal\node\Form\NodeForm given, called in /data/app/modules/test/test.module on line 5 in test_deprecated_autoloader() (line 8 of /data/app/modules/test/test.module). (edited) 

The biggest issue here is that $isNodeForm = $form_object instanceof NodeForm; will quietly (e.g. no error or deprecation warning) result to false, leading to unexpected changes.

Steps to reproduce

Evaluate $form_object instanceof \Drupal\node\NodeForm\NodeForm on an instance of Drupal\node\Form\NodeForm - this will evaluate to false.

Proposed resolution

NodeForm is an internal class but I bet many have used it this way - does this need special handling or is this more a documentation task to update the change records / record this behaviour somewhere?

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Active

Version

11.0 🔥

Component

base system

Created by

🇳🇿New Zealand ericgsmith

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024