From 6c0b5518628a852e5b503c3e7844cbaf546ebfc6 Mon Sep 17 00:00:00 2001
From: Benjamin Franzke <ben@bnf.dev>
Date: Mon, 9 Oct 2023 20:57:34 +0200
Subject: [PATCH] [TASK] Add phpstan check for unneeded pseudo uncertain
 instanceof usage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

An `instanceof Type` on `Type|null` is unneeded and is to be replaced by
a null-check (or modern alternatives like optional chaning or the null
coalescing operator) in order to avoid narrowing code branches
unnecessarily. We call them "pseudo" uncertain checks there is no need
to express uncertainty regarding the type in a condition where native
type declarations define a specific type *or* null:

  It is `null` or `!null`.

Definition of a pseudo uncertain instanceof check:

  `$foo instanceof Bar` is fully equivalent to `$foo !== null`,
    when `$foo` is defined (via native PHP types) to be `Bar|null`.
   ⇒ `instanceof` expresses pseudo uncertainty regarding the type.

From what we have seen in previous gerrit discussions, there were two
reasons why instanceof was preferred over null checks although being
unneeded:

1) Cognitive load for an instanceof check is perceived to be lower in
   contrast to negated null (not null) conditions
2) Preparatory safe-guard against type of $foo being changed at sometime
   later

1) Cognitive load is a subjective term and the opinions actually differ
   a lot. Some developers prefer narrowing instanceof conditions because
   they claim the desired type for a certain code branch.
   Some others say that's a clear signal for code that needs refactoring
   and perceive a high cognitive load because they do not understand why
   the type is unnecessarily checked if it can only be null or not null.
   Lets call that: "reverse cognitive load".
   That means, this argument basically boils down to
   "congitive load" (for the good "then" case: inner code block) vs
   "reverse cognitive load" (for the bad "else" case: outer code block)
   ⇒ Due to being subjective "cognitive load" is not a good argument to
     base a decision upon.

2) The second argument is that an instanceof ensures a method that is to
   be called actually exists and doesn't lead to an error – that is a
   "preparatory safe-guard".
   This is true and works, but doesn't "answer" the question,
   what happens if the object is not an instance of the desired type
   (but not null).
   While preparatory safe-guards against the type of variable being
   changed sometime later was probably a pretty good idea for code that
   is not statically analyzed and had no native type declarations, but
   such checks effectively preclude that the type must/should never
   change (which might not be true!) and has no chance of actually
   detecting when that case (type change/extension) ever happens.
   All advantages offered by pseudo uncertain instanceof checks are
   accomplished with static code analysis as well, but with the added
   downside that an `instanceof` hardcodes our human static code
   analysis result, instead of letting the static analyzer do the job.

   To explain that:
   If the type of the variable under test is actually widened (like a
   union type, or change to a base class), it will never be
   automatically detected that there is an instanceof condition that
   restricts the type too narrowly. It will always be valid code from
   static code analysis perspective.

   In comparison to that, static analysis on null-checked variables will
   report invalid method calls or assignments not allowed by the
   (natively defined) types and will notify in case a type change
   requires the code to be adapted.
   We gain the advantage that the code will not be forgotten to
   be updated to a new type.

   That means !== null combined with static code analysis has the same
   level of being a safeguard against the bad cases, while instanceof
   silently transforms new "good"-cases into bugs, where !== null is a
   transparent and secure passthrough.

   Actually to make an uncertain instanceof robust, an elseif branch
   would be needed to be somehow notified about new good-cases without
   silently ignoring them:

   if ($foo instanceof Foo) {
       …
   } elseif ($foo !== null) {
       throw new MustNeverHappenException(…);
   }

In other words an unneeded pseudo uncertain instanceof check is
basically like a switch construct without a default case.
Just to be explicit: Of course, instanceof is fine to be used
when multiples types are to be expected and handled in different code
branches.

That means pseudo uncertain instanceof usage instead of null-checks is
an antipattern for the following reasons:

 * It narrow code branches for the sake of less cognitive load
   * The cognitive load appears to be lower, but actually future-bad
     cases are overseen and are never auto-detectable in future – while
     null-checks will resolve to static analysis errors in case the
     input type is *ever* widened (which uncertain `instanceof` checks
     try to prepare for, but actually introduce future-bugs because of
     missing `else` cases)
 * It embraces deep nesting instead of early returns via null-checks
 * It embraces conditions over newer and more elegant PHP techniques
   like optional chaing
 * Tries to "help" the developer by explicitly anotating the
   current type of the variable under test
   ⇒ This is a clear sign of code smell, that needs to refactored into
      smaller chunks and methods and type autocompletion/information
      can be provided by IDEs when using proper types (which this change
      is about) anyway
 * Has zero advantages over static code analysis

Resolves: #102140
Releases: main, 12.4
Change-Id: I10de41e9744a814c9e24255573b5a5eaf6fb8b0f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/80859
Tested-by: Andreas Kienast <a.fernandez@scripting-base.de>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
---
 Build/phpstan/phpstan.neon                    | 11 +++
 .../Rules/Classes/UnneededInstanceOfRule.php  | 84 +++++++++++++++++++
 composer.json                                 |  3 +-
 .../Modules/Debug/QueryInformation.php        |  2 +-
 .../Controller/AjaxLoginController.php        |  5 +-
 .../PageTsConfigActiveController.php          |  3 +-
 .../PageTsConfigIncludesController.php        | 20 ++---
 .../backend/Classes/Http/RouteDispatcher.php  |  2 +-
 .../CspAjaxController.php                     |  2 +-
 .../Buttons/DropDown/AbstractDropDownItem.php |  4 +-
 .../Components/Buttons/DropDownButton.php     |  4 +-
 .../Components/Buttons/GenericButton.php      |  4 +-
 .../Classes/View/BackendLayoutView.php        |  5 +-
 .../Domain/Repository/PageRepository.php      |  8 +-
 .../Error/AbstractExceptionHandler.php        |  2 +-
 .../Error/ProductionExceptionHandler.php      |  7 +-
 .../core/Classes/Imaging/IconFactory.php      | 18 ++--
 .../Classes/Messaging/FlashMessageQueue.php   |  6 +-
 .../core/Classes/Routing/PageRouter.php       |  2 +-
 .../TypoScript/PageTsConfigFactory.php        |  2 +-
 .../Controller/DashboardController.php        |  2 +-
 .../DashboardInitializationService.php        |  7 +-
 .../Persistence/Generic/Mapper/DataMapper.php |  6 +-
 .../Classes/Utility/DependencyUtility.php     |  2 +-
 .../Classes/Utility/InstallUtility.php        |  5 +-
 .../Classes/Utility/ListUtility.php           | 23 ++---
 .../RecoveryConfigurationTest.php             |  4 +-
 .../Persistence/FormPersistenceManager.php    |  5 +-
 .../ContentObject/FilesContentObject.php      |  5 +-
 .../Classes/Controller/ErrorController.php    |  8 +-
 .../Middleware/BackendUserAuthenticator.php   |  2 +-
 .../Middleware/SiteBaseRedirectResolver.php   |  2 +-
 .../Classes/Typolink/PageLinkBuilder.php      | 18 +---
 .../Classes/Controller/ExportController.php   |  4 +-
 .../Classes/Controller/ImportController.php   |  5 +-
 typo3/sysext/impexp/Classes/Export.php        |  2 +-
 .../Classes/Middleware/Maintenance.php        |  2 +-
 .../Hooks/DataHandlerSlugUpdateHook.php       |  8 +-
 .../Http/Middleware/RedirectHandler.php       | 48 +++++------
 typo3/sysext/scheduler/Classes/Scheduler.php  |  2 +-
 .../Controller/TemplateAnalyzerController.php |  9 +-
 .../Classes/Middleware/WorkspacePreview.php   |  6 +-
 42 files changed, 210 insertions(+), 159 deletions(-)
 create mode 100644 Build/phpstan/src/Rules/Classes/UnneededInstanceOfRule.php

diff --git a/Build/phpstan/phpstan.neon b/Build/phpstan/phpstan.neon
index beda53b53970..75c67e6f8e30 100644
--- a/Build/phpstan/phpstan.neon
+++ b/Build/phpstan/phpstan.neon
@@ -4,6 +4,17 @@ includes:
   - ../../vendor/friendsoftypo3/phpstan-typo3/extension.neon
   - ../../vendor/phpstan/phpstan-phpunit/extension.neon
 
+services:
+  -
+    class: TYPO3\CMS\PHPStan\Rules\Classes\UnneededInstanceOfRule
+    arguments:
+      # treatPhpDocTypesAsCertain is explicitly disabled as long as we have ignored errors
+      # in our baseline, as that we MUST not trust doc types 100%.
+      # We can switch to the global parameter `%treatPhpDocTypesAsCertain%` once that's fixed.
+      treatPhpDocTypesAsCertain: false
+    tags:
+      - phpstan.rules.rule
+
 parameters:
   # Use local .cache dir instead of /tmp
   tmpDir: ../../.cache/phpstan
diff --git a/Build/phpstan/src/Rules/Classes/UnneededInstanceOfRule.php b/Build/phpstan/src/Rules/Classes/UnneededInstanceOfRule.php
new file mode 100644
index 000000000000..20cde9b36e63
--- /dev/null
+++ b/Build/phpstan/src/Rules/Classes/UnneededInstanceOfRule.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\PHPStan\Rules\Classes;
+
+use PhpParser\Node;
+use PHPStan\Analyser\Scope;
+use PHPStan\Rules\Rule;
+use PHPStan\Rules\RuleErrorBuilder;
+use PHPStan\Type\BooleanType;
+use PHPStan\Type\Constant\ConstantBooleanType;
+use PHPStan\Type\ObjectType;
+use PHPStan\Type\TypeCombinator;
+use PHPStan\Type\VerbosityLevel;
+
+/**
+ * @implements Rule<Node\Expr\Instanceof_>
+ */
+class UnneededInstanceOfRule implements Rule
+{
+    public function __construct(
+        private readonly bool $treatPhpDocTypesAsCertain,
+    ) {
+    }
+
+    public function getNodeType(): string
+    {
+        return Node\Expr\Instanceof_::class;
+    }
+
+    public function processNode(Node $node, Scope $scope): array
+    {
+        $instanceofType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node) : $scope->getNativeType($node);
+
+        if ($instanceofType instanceof ConstantBooleanType) {
+            return [];
+        }
+        if (!$instanceofType instanceof BooleanType) {
+            return [];
+        }
+        if (!$node->expr instanceof Node\Expr\Variable) {
+            return [];
+        }
+
+        if ($node->class instanceof Node\Name) {
+            $className = $scope->resolveName($node->class);
+            $classType = new ObjectType($className);
+        } else {
+            $classType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->class) : $scope->getNativeType($node->class);
+        }
+
+        $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->expr) : $scope->getNativeType($node->expr);
+        if (TypeCombinator::containsNull($exprType)) {
+            $nonNullType = TypeCombinator::removeNull($exprType);
+
+            if ($nonNullType instanceof ObjectType && $nonNullType->equals($classType)) {
+                return [
+                    RuleErrorBuilder::message(
+                        sprintf(
+                            'Unneeded instanceof on %s|null. Use a null check instead.',
+                            $nonNullType->describe(VerbosityLevel::typeOnly())
+                        )
+                    )->identifier('instanceof.unneededNotNullSubstitute')->build(),
+                ];
+            }
+        }
+
+        return [];
+    }
+}
diff --git a/composer.json b/composer.json
index e6c2c6c64f25..b04da23ca802 100644
--- a/composer.json
+++ b/composer.json
@@ -316,7 +316,8 @@
 			"TYPO3Tests\\TestTyposcriptPagetsconfigfactory\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_typoscript_pagetsconfigfactory/Classes/",
 			"TYPO3Tests\\TestTsconfigEvent\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_tsconfig_event/Classes/",
 			"TYPO3Tests\\TypeConverterTest\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/type_converter_test/Classes/",
-			"TYPO3Tests\\ViewhelperLibrary\\": "typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/"
+			"TYPO3Tests\\ViewhelperLibrary\\": "typo3/sysext/fluid/Tests/Functional/Fixtures/Libraries/viewhelper_library/src/",
+			"TYPO3\\CMS\\PHPStan\\": "Build/phpstan/src/"
 		}
 	}
 }
diff --git a/typo3/sysext/adminpanel/Classes/Modules/Debug/QueryInformation.php b/typo3/sysext/adminpanel/Classes/Modules/Debug/QueryInformation.php
index 9eba7cf39cbd..7de08c04ee0f 100644
--- a/typo3/sysext/adminpanel/Classes/Modules/Debug/QueryInformation.php
+++ b/typo3/sysext/adminpanel/Classes/Modules/Debug/QueryInformation.php
@@ -66,7 +66,7 @@ class QueryInformation extends AbstractSubModule implements DataProviderInterfac
         }
 
         $data = [];
-        if ($loggingMiddleware instanceof DoctrineSqlLoggingMiddleware) {
+        if ($loggingMiddleware !== null) {
             $queries = $loggingMiddleware->getQueries();
             $data['totalQueries'] = count($queries);
             $data['queries'] = $this->groupQueries($queries);
diff --git a/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php b/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
index aced6f2c57a8..d0350700820c 100644
--- a/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
+++ b/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
@@ -136,7 +136,10 @@ class AjaxLoginController
     protected function isAuthorizedBackendSession()
     {
         $backendUser = $this->getBackendUser();
-        return $backendUser instanceof BackendUserAuthentication && isset($backendUser->user['uid']);
+        if ($backendUser === null) {
+            return false;
+        }
+        return isset($backendUser->user['uid']);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigActiveController.php b/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigActiveController.php
index afc582060254..475c42964d07 100644
--- a/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigActiveController.php
+++ b/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigActiveController.php
@@ -44,7 +44,6 @@ use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionAggregator
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionEnforcerVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSetupConditionConstantSubstitutionVisitor;
 use TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer;
-use TYPO3\CMS\Core\TypoScript\UserTsConfig;
 
 /**
  * Page TSconfig > Active page TSconfig
@@ -133,7 +132,7 @@ final class PageTsConfigActiveController
 
         // Overload tree with user TSconfig if any
         $userTsConfig = $backendUser->getUserTsConfig();
-        if (!$userTsConfig instanceof UserTsConfig) {
+        if ($userTsConfig === null) {
             throw new \RuntimeException('User TSconfig not initialized', 1674609098);
         }
         $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
diff --git a/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigIncludesController.php b/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigIncludesController.php
index 412a4e274936..85c53193743d 100644
--- a/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigIncludesController.php
+++ b/typo3/sysext/backend/Classes/Controller/PageTsConfig/PageTsConfigIncludesController.php
@@ -32,7 +32,6 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Site\Entity\Site;
-use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\IncludeInterface;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\RootInclude;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\SiteInclude;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\TsConfigInclude;
@@ -45,9 +44,7 @@ use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeNodeFinderVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSetupConditionConstantSubstitutionVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSourceAggregatorVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSyntaxScannerVisitor;
-use TYPO3\CMS\Core\TypoScript\Tokenizer\Line\LineStream;
 use TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer;
-use TYPO3\CMS\Core\TypoScript\UserTsConfig;
 
 /**
  * Page TSconfig > Included page TSconfig
@@ -118,7 +115,7 @@ final class PageTsConfigIncludesController
 
         // Overload tree with user TSconfig if any
         $userTsConfig = $backendUser->getUserTsConfig();
-        if (!$userTsConfig instanceof UserTsConfig) {
+        if ($userTsConfig === null) {
             throw new \RuntimeException('User TSconfig not initialized', 1675535278);
         }
         $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
@@ -202,7 +199,7 @@ final class PageTsConfigIncludesController
 
             // Overload tree with user TSconfig if any
             $userTsConfig = $backendUser->getUserTsConfig();
-            if (!$userTsConfig instanceof UserTsConfig) {
+            if ($userTsConfig === null) {
                 throw new \RuntimeException('UserTsConfig not initialized', 1675535279);
             }
             $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
@@ -227,20 +224,15 @@ final class PageTsConfigIncludesController
         $nodeFinderVisitor->setNodeIdentifier($includeIdentifier);
         $treeTraverser = new IncludeTreeTraverser();
         $treeTraverser->traverse($includeTree, [$nodeFinderVisitor]);
-        $foundNode = $nodeFinderVisitor->getFoundNode();
-
-        if (!$foundNode instanceof IncludeInterface) {
-            return $this->responseFactory->createResponse(400);
-        }
-        $lineStream = $foundNode->getLineStream();
-        if (!$lineStream instanceof LineStream) {
+        $lineStream = $nodeFinderVisitor->getFoundNode()?->getLineStream();
+        if ($lineStream === null) {
             return $this->responseFactory->createResponse(400);
         }
 
         return $this->responseFactory
             ->createResponse()
             ->withHeader('Content-Type', 'text/plain')
-            ->withBody($this->streamFactory->createStream((string)$foundNode->getLineStream()));
+            ->withBody($this->streamFactory->createStream((string)$lineStream));
     }
 
     public function sourceWithIncludesAction(ServerRequestInterface $request): ResponseInterface
@@ -278,7 +270,7 @@ final class PageTsConfigIncludesController
 
             // Overload tree with user TSconfig if any
             $userTsConfig = $backendUser->getUserTsConfig();
-            if (!$userTsConfig instanceof UserTsConfig) {
+            if ($userTsConfig === null) {
                 throw new \RuntimeException('UserTsConfig not initialized', 1675535280);
             }
             $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
diff --git a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php
index 724777239750..6da95720ef5b 100644
--- a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php
+++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php
@@ -63,7 +63,7 @@ class RouteDispatcher extends Dispatcher
         $route = $request->getAttribute('route');
 
         $enforceReferrerResponse = $this->enforceReferrer($request, $route);
-        if ($enforceReferrerResponse instanceof ResponseInterface) {
+        if ($enforceReferrerResponse !== null) {
             return $enforceReferrerResponse;
         }
         // Ensure that a token exists, and the token is requested, if the route requires a valid token
diff --git a/typo3/sysext/backend/Classes/Security/ContentSecurityPolicy/CspAjaxController.php b/typo3/sysext/backend/Classes/Security/ContentSecurityPolicy/CspAjaxController.php
index 4e6b8c819b41..514017ceb687 100644
--- a/typo3/sysext/backend/Classes/Security/ContentSecurityPolicy/CspAjaxController.php
+++ b/typo3/sysext/backend/Classes/Security/ContentSecurityPolicy/CspAjaxController.php
@@ -92,7 +92,7 @@ class CspAjaxController
         if ($action === 'deleteReports') {
             return $this->deleteReportsAction($scope);
         }
-        if ($action === 'handleReport' && $uuid instanceof UuidV4) {
+        if ($action === 'handleReport' && $uuid !== null) {
             return $this->handleReportAction($uuid);
         }
         if ($action === 'mutateReport'
diff --git a/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDown/AbstractDropDownItem.php b/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDown/AbstractDropDownItem.php
index ab627d4d6a62..10ddca70b098 100644
--- a/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDown/AbstractDropDownItem.php
+++ b/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDown/AbstractDropDownItem.php
@@ -46,9 +46,7 @@ abstract class AbstractDropDownItem implements \Stringable
 
     public function setIcon(?Icon $icon): self
     {
-        if ($icon instanceof Icon) {
-            $icon->setSize(IconSize::SMALL);
-        }
+        $icon?->setSize(IconSize::SMALL);
         $this->icon = $icon;
         return $this;
     }
diff --git a/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDownButton.php b/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDownButton.php
index 4387c0808845..e29ef1acea5a 100644
--- a/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDownButton.php
+++ b/typo3/sysext/backend/Classes/Template/Components/Buttons/DropDownButton.php
@@ -59,9 +59,7 @@ class DropDownButton implements ButtonInterface
 
     public function setIcon(?Icon $icon): self
     {
-        if ($icon instanceof Icon) {
-            $icon->setSize(IconSize::SMALL);
-        }
+        $icon?->setSize(IconSize::SMALL);
         $this->icon = $icon;
         return $this;
     }
diff --git a/typo3/sysext/backend/Classes/Template/Components/Buttons/GenericButton.php b/typo3/sysext/backend/Classes/Template/Components/Buttons/GenericButton.php
index b7269e9e507d..8c13edd67e10 100644
--- a/typo3/sysext/backend/Classes/Template/Components/Buttons/GenericButton.php
+++ b/typo3/sysext/backend/Classes/Template/Components/Buttons/GenericButton.php
@@ -59,9 +59,7 @@ class GenericButton implements ButtonInterface
 
     public function setIcon(?Icon $icon): self
     {
-        if ($icon instanceof Icon) {
-            $icon->setSize(IconSize::SMALL);
-        }
+        $icon?->setSize(IconSize::SMALL);
         $this->icon = $icon;
         return $this;
     }
diff --git a/typo3/sysext/backend/Classes/View/BackendLayoutView.php b/typo3/sysext/backend/Classes/View/BackendLayoutView.php
index ade23d1ccf66..c9e01662dcab 100644
--- a/typo3/sysext/backend/Classes/View/BackendLayoutView.php
+++ b/typo3/sysext/backend/Classes/View/BackendLayoutView.php
@@ -302,10 +302,7 @@ class BackendLayoutView implements SingletonInterface
     public function getSelectedBackendLayout($pageId)
     {
         $layout = $this->getBackendLayoutForPage((int)$pageId);
-        if ($layout instanceof BackendLayout) {
-            return $layout->getStructure();
-        }
-        return null;
+        return $layout?->getStructure();
     }
 
     /**
diff --git a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
index 68d2650e53a0..2087885633cf 100644
--- a/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
+++ b/typo3/sysext/core/Classes/Domain/Repository/PageRepository.php
@@ -1307,11 +1307,9 @@ class PageRepository implements LoggerAwareInterface
         }
         $validPageIds = [];
         $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
-        if ($restrictionContainer instanceof QueryRestrictionContainerInterface) {
-            $queryBuilder->setRestrictions($restrictionContainer);
-        } else {
-            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
-        }
+        $queryBuilder->setRestrictions(
+            $restrictionContainer ?? GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
+        );
         $statement = $queryBuilder->select('uid')
             ->from('pages')
             ->where(
diff --git a/typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php b/typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php
index 2ba3f4f2c656..0955cd60db80 100644
--- a/typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php
+++ b/typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php
@@ -149,7 +149,7 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, Si
         $workspace = 0;
         $data = [];
         $backendUser = $this->getBackendUser();
-        if ($backendUser instanceof BackendUserAuthentication) {
+        if ($backendUser !== null) {
             if (isset($backendUser->user['uid'])) {
                 $userId = $backendUser->user['uid'];
             }
diff --git a/typo3/sysext/core/Classes/Error/ProductionExceptionHandler.php b/typo3/sysext/core/Classes/Error/ProductionExceptionHandler.php
index b43cd8f6cd2a..41d447587ed5 100644
--- a/typo3/sysext/core/Classes/Error/ProductionExceptionHandler.php
+++ b/typo3/sysext/core/Classes/Error/ProductionExceptionHandler.php
@@ -15,7 +15,6 @@
 
 namespace TYPO3\CMS\Core\Error;
 
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Controller\ErrorPageController;
 use TYPO3\CMS\Core\Error\Http\AbstractClientErrorException;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -106,10 +105,10 @@ class ProductionExceptionHandler extends AbstractExceptionHandler
         }
         // Only show errors if a BE user is authenticated
         $backendUser = $this->getBackendUser();
-        if ($backendUser instanceof BackendUserAuthentication) {
-            return ($backendUser->user['uid'] ?? 0) > 0;
+        if ($backendUser === null) {
+            return false;
         }
-        return false;
+        return ($backendUser->user['uid'] ?? 0) > 0;
     }
 
     /**
diff --git a/typo3/sysext/core/Classes/Imaging/IconFactory.php b/typo3/sysext/core/Classes/Imaging/IconFactory.php
index 064b63e2a7df..addac51fed95 100644
--- a/typo3/sysext/core/Classes/Imaging/IconFactory.php
+++ b/typo3/sysext/core/Classes/Imaging/IconFactory.php
@@ -86,17 +86,15 @@ class IconFactory
      */
     public function getIcon($identifier, string|IconSize $size = IconSize::MEDIUM, $overlayIdentifier = null, \TYPO3\CMS\Core\Type\Icon\IconState|IconState $state = null)
     {
-        if ($state instanceof IconState) {
-            $stateValue = $state->value;
-        } else {
-            if ($state instanceof \TYPO3\CMS\Core\Type\Icon\IconState) {
-                trigger_error(
-                    'Using the non-native enumeration TYPO3\CMS\Core\Type\Icon\IconState in IconFactory->getIcon()'
-                    . ' will not work in TYPO3 v14.0 anymore. Use native TYPO3\CMS\Core\Imaging\IconState instead.',
-                    E_USER_DEPRECATED
-                );
-            }
+        if ($state instanceof \TYPO3\CMS\Core\Type\Icon\IconState) {
+            trigger_error(
+                'Using the non-native enumeration TYPO3\CMS\Core\Type\Icon\IconState in IconFactory->getIcon()'
+                . ' will not work in TYPO3 v14.0 anymore. Use native TYPO3\CMS\Core\Imaging\IconState instead.',
+                E_USER_DEPRECATED
+            );
             $stateValue = (string)$state;
+        } else {
+            $stateValue = $state?->value ?? '';
         }
         if (is_string($size)) {
             $size = IconSize::from($size);
diff --git a/typo3/sysext/core/Classes/Messaging/FlashMessageQueue.php b/typo3/sysext/core/Classes/Messaging/FlashMessageQueue.php
index c1fa5c07de27..9ee8d3ba0a02 100644
--- a/typo3/sysext/core/Classes/Messaging/FlashMessageQueue.php
+++ b/typo3/sysext/core/Classes/Messaging/FlashMessageQueue.php
@@ -156,9 +156,7 @@ class FlashMessageQueue extends \SplQueue implements \JsonSerializable
             $flashMessages = array_map('json_encode', $flashMessages);
         }
         $user = $this->getUserByContext();
-        if ($user instanceof AbstractUserAuthentication) {
-            $user->setAndSaveSessionData($this->identifier, $flashMessages);
-        }
+        $user?->setAndSaveSessionData($this->identifier, $flashMessages);
     }
 
     /**
@@ -194,7 +192,7 @@ class FlashMessageQueue extends \SplQueue implements \JsonSerializable
     {
         $sessionMessages = [];
         $user = $this->getUserByContext();
-        if ($user instanceof AbstractUserAuthentication) {
+        if ($user !== null) {
             $messagesFromSession = $user->getSessionData($this->identifier);
             $messagesFromSession = is_array($messagesFromSession) ? $messagesFromSession : [];
             foreach ($messagesFromSession as $messageData) {
diff --git a/typo3/sysext/core/Classes/Routing/PageRouter.php b/typo3/sysext/core/Classes/Routing/PageRouter.php
index 6e05a40d1693..3d61b4180b5a 100644
--- a/typo3/sysext/core/Classes/Routing/PageRouter.php
+++ b/typo3/sysext/core/Classes/Routing/PageRouter.php
@@ -97,7 +97,7 @@ class PageRouter implements RouterInterface
      */
     public function matchRequest(ServerRequestInterface $request, RouteResultInterface $previousResult = null): RouteResultInterface
     {
-        if (!($previousResult instanceof RouteResultInterface)) {
+        if ($previousResult === null) {
             throw new RouteNotFoundException('No previous result given. Cannot find a page for an empty route part', 1555303496);
         }
 
diff --git a/typo3/sysext/core/Classes/TypoScript/PageTsConfigFactory.php b/typo3/sysext/core/Classes/TypoScript/PageTsConfigFactory.php
index 618426bbb34e..7633a69484e8 100644
--- a/typo3/sysext/core/Classes/TypoScript/PageTsConfigFactory.php
+++ b/typo3/sysext/core/Classes/TypoScript/PageTsConfigFactory.php
@@ -58,7 +58,7 @@ final class PageTsConfigFactory
         $pagesTsConfigTree = $this->tsConfigTreeBuilder->getPagesTsConfigTree($fullRootLine, $this->tokenizer, $this->cache);
 
         // Overloading with user TSconfig if hand over
-        if ($userTsConfig instanceof UserTsConfig) {
+        if ($userTsConfig !== null) {
             $userTsConfigAst = $userTsConfig->getUserTsConfigTree();
             $userTsConfigPageOverrides = '';
             // @todo: This is ugly and expensive. There should be a better way to do this. Similar in BE page TSconfig controllers.
diff --git a/typo3/sysext/dashboard/Classes/Controller/DashboardController.php b/typo3/sysext/dashboard/Classes/Controller/DashboardController.php
index abf702816c11..90936e79e13b 100644
--- a/typo3/sysext/dashboard/Classes/Controller/DashboardController.php
+++ b/typo3/sysext/dashboard/Classes/Controller/DashboardController.php
@@ -118,7 +118,7 @@ class DashboardController
                 (int)$this->getBackendUser()->user['uid'],
                 $parameters['dashboard-title'] ?? ''
             );
-            if ($dashboard instanceof Dashboard) {
+            if ($dashboard !== null) {
                 $this->saveCurrentDashboard($dashboard->getIdentifier());
             }
         }
diff --git a/typo3/sysext/dashboard/Classes/DashboardInitializationService.php b/typo3/sysext/dashboard/Classes/DashboardInitializationService.php
index f42c61935df8..ee8aaba0ab9f 100644
--- a/typo3/sysext/dashboard/Classes/DashboardInitializationService.php
+++ b/typo3/sysext/dashboard/Classes/DashboardInitializationService.php
@@ -67,7 +67,7 @@ class DashboardInitializationService
     protected function defineCurrentDashboard(): Dashboard
     {
         $currentDashboard = $this->dashboardRepository->getDashboardByIdentifier($this->loadCurrentDashboard($this->user));
-        if (!$currentDashboard instanceof Dashboard) {
+        if ($currentDashboard === null) {
             $dashboards = $this->getDashboardsForUser();
             /** @var Dashboard $currentDashboard */
             $currentDashboard = reset($dashboards);
@@ -94,9 +94,10 @@ class DashboardInitializationService
                     (int)$this->user->user['uid']
                 );
 
-                if ($dashboard instanceof Dashboard) {
-                    $dashboardsForUser[$dashboard->getIdentifier()] = $dashboard;
+                if ($dashboard === null) {
+                    continue;
                 }
+                $dashboardsForUser[$dashboard->getIdentifier()] = $dashboard;
             }
         }
 
diff --git a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
index 386889ab4347..86777ad58d76 100644
--- a/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
+++ b/typo3/sysext/extbase/Classes/Persistence/Generic/Mapper/DataMapper.php
@@ -674,7 +674,7 @@ class DataMapper
             ->getProperty($propertyName)
             ->getPrimaryType();
 
-        if (!$primaryType instanceof Type) {
+        if ($primaryType === null) {
             throw NoPropertyTypesException::create($parentObject::class, $propertyName);
         }
 
@@ -722,7 +722,7 @@ class DataMapper
             $property = $this->reflectionService->getClassSchema(get_class($parentObject))->getProperty($propertyName);
             $primaryType = $property->getPrimaryType();
 
-            if (!$primaryType instanceof Type) {
+            if ($primaryType === null) {
                 throw NoPropertyTypesException::create($parentObject::class, $propertyName);
             }
 
@@ -831,7 +831,7 @@ class DataMapper
                 ->getProperty($propertyName)
                 ->getPrimaryType();
 
-            if (!$primaryType instanceof Type) {
+            if ($primaryType === null) {
                 throw NoPropertyTypesException::create($parentClassName, $propertyName);
             }
 
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/DependencyUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/DependencyUtility.php
index 7dde0a0d6789..d12f821114cd 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/DependencyUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/DependencyUtility.php
@@ -340,7 +340,7 @@ class DependencyUtility implements SingletonInterface
         }
 
         $latestCompatibleExtensionByDependency = $this->getLatestCompatibleExtensionByDependency($dependency);
-        if (!$latestCompatibleExtensionByDependency instanceof Extension) {
+        if ($latestCompatibleExtensionByDependency === null) {
             if (!$this->skipDependencyCheck) {
                 throw new MissingExtensionDependencyException(
                     'Could not resolve dependency for "' . $dependency->getIdentifier() . '"',
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
index 94e42ccc536c..1ae5da6e5e81 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/InstallUtility.php
@@ -389,10 +389,7 @@ class InstallUtility implements LoggerAwareInterface
             }
         }
         $newSites = array_diff_key($siteConfiguration->resolveAllExistingSites(false), $existingSites);
-        $importedPages = [];
-        if ($import instanceof Import) {
-            $importedPages = $import->getImportMapId()['pages'] ?? null;
-        }
+        $importedPages = $import?->getImportMapId()['pages'] ?? [];
         $newSiteIdentifierList = [];
         foreach ($newSites as $newSite) {
             $exportedPageId = $newSite->getRootPageId();
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
index 45f5a0a0953b..9aabed6099a6 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/ListUtility.php
@@ -209,17 +209,20 @@ class ListUtility implements SingletonInterface
         $extensions = $this->enrichExtensionsWithEmConfInformation($extensions);
         foreach ($extensions as $extensionKey => $properties) {
             $terObject = $this->getExtensionTerData($extensionKey, $extensions[$extensionKey]['version'] ?? '');
-            if ($terObject instanceof Extension) {
-                $extensions[$extensionKey]['terObject'] = $terObject;
-                $extensions[$extensionKey]['remote'] = $terObject->getRemoteIdentifier();
-                $extensions[$extensionKey]['updateAvailable'] = false;
-                $extensions[$extensionKey]['updateToVersion'] = null;
-                $extensionToUpdate = $this->getUpdateableVersion($terObject);
-                if ($extensionToUpdate instanceof Extension) {
-                    $extensions[$extensionKey]['updateAvailable'] = true;
-                    $extensions[$extensionKey]['updateToVersion'] = $extensionToUpdate;
-                }
+            if ($terObject === null) {
+                continue;
+            }
+            $extensions[$extensionKey]['terObject'] = $terObject;
+            $extensions[$extensionKey]['remote'] = $terObject->getRemoteIdentifier();
+            $extensions[$extensionKey]['updateAvailable'] = false;
+            $extensions[$extensionKey]['updateToVersion'] = null;
+
+            $extensionToUpdate = $this->getUpdateableVersion($terObject);
+            if ($extensionToUpdate === null) {
+                continue;
             }
+            $extensions[$extensionKey]['updateAvailable'] = true;
+            $extensions[$extensionKey]['updateToVersion'] = $extensionToUpdate;
         }
         return $extensions;
     }
diff --git a/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php b/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php
index 2391fa7e4187..d0bbb8af0afd 100644
--- a/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php
+++ b/typo3/sysext/felogin/Tests/Unit/Configuration/RecoveryConfigurationTest.php
@@ -61,9 +61,7 @@ final class RecoveryConfigurationTest extends UnitTestCase
 
     protected function setupSubject(Context $context = null): void
     {
-        if (!$context instanceof Context) {
-            $context = new Context();
-        }
+        $context ??= new Context();
 
         $this->configurationManager->method('getConfiguration')->with(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS)
             ->willReturn($this->settings);
diff --git a/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php
index 135fd374ea24..b518e04425a1 100644
--- a/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php
+++ b/typo3/sysext/form/Classes/Mvc/Persistence/FormPersistenceManager.php
@@ -728,10 +728,7 @@ class FormPersistenceManager implements FormPersistenceManagerInterface
     protected function getStorageByUid(int $storageUid): ResourceStorage
     {
         $storage = $this->storageRepository->findByUid($storageUid);
-        if (
-            !$storage instanceof ResourceStorage
-            || !$storage->isBrowsable()
-        ) {
+        if (!$storage?->isBrowsable()) {
             throw new PersistenceManagerException(sprintf('Could not access storage with uid "%d".', $storageUid), 1471630581);
         }
         return $storage;
diff --git a/typo3/sysext/frontend/Classes/ContentObject/FilesContentObject.php b/typo3/sysext/frontend/Classes/ContentObject/FilesContentObject.php
index fcf55e9da147..3ab2b4b8f55a 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/FilesContentObject.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/FilesContentObject.php
@@ -18,7 +18,6 @@ namespace TYPO3\CMS\Frontend\ContentObject;
 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3\CMS\Frontend\Resource\FileCollector;
 
 /**
@@ -57,7 +56,7 @@ class FilesContentObject extends AbstractContentObject
         $limit = (int)$this->cObj->stdWrapValue('maxItems', $conf, $availableFileObjectCount);
         $end = MathUtility::forceIntegerInRange($start + $limit, $start, $availableFileObjectCount);
 
-        if ($frontendController instanceof TypoScriptFrontendController) {
+        if ($frontendController !== null) {
             $frontendController->register['FILES_COUNT'] = min($limit, $availableFileObjectCount);
         }
         $fileObjectCounter = 0;
@@ -68,7 +67,7 @@ class FilesContentObject extends AbstractContentObject
             $key = $keys[$i];
             $fileObject = $fileObjects[$key];
 
-            if ($frontendController instanceof TypoScriptFrontendController) {
+            if ($frontendController !== null) {
                 $frontendController->register['FILE_NUM_CURRENT'] = $fileObjectCounter;
             }
             $this->cObj->setCurrentFile($fileObject);
diff --git a/typo3/sysext/frontend/Classes/Controller/ErrorController.php b/typo3/sysext/frontend/Classes/Controller/ErrorController.php
index 6d1320d79ec3..48152992db1e 100644
--- a/typo3/sysext/frontend/Classes/Controller/ErrorController.php
+++ b/typo3/sysext/frontend/Classes/Controller/ErrorController.php
@@ -48,7 +48,7 @@ class ErrorController
             throw new InternalServerErrorException($message, 1607585445);
         }
         $errorHandler = $this->getErrorHandlerFromSite($request, 500);
-        if ($errorHandler instanceof PageErrorHandlerInterface) {
+        if ($errorHandler !== null) {
             return $errorHandler->handlePageError($request, $message, $reasons);
         }
         return $this->handleDefaultError($request, 500, $message ?: 'Internal Server Error');
@@ -66,7 +66,7 @@ class ErrorController
             throw new ServiceUnavailableException($message, 1518472181);
         }
         $errorHandler = $this->getErrorHandlerFromSite($request, 503);
-        if ($errorHandler instanceof PageErrorHandlerInterface) {
+        if ($errorHandler !== null) {
             return $errorHandler->handlePageError($request, $message, $reasons);
         }
         return $this->handleDefaultError($request, 503, $message ?: 'Service Unavailable');
@@ -81,7 +81,7 @@ class ErrorController
     public function pageNotFoundAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
     {
         $errorHandler = $this->getErrorHandlerFromSite($request, 404);
-        if ($errorHandler instanceof PageErrorHandlerInterface) {
+        if ($errorHandler !== null) {
             return $errorHandler->handlePageError($request, $message, $reasons);
         }
         try {
@@ -100,7 +100,7 @@ class ErrorController
     public function accessDeniedAction(ServerRequestInterface $request, string $message, array $reasons = []): ResponseInterface
     {
         $errorHandler = $this->getErrorHandlerFromSite($request, 403);
-        if ($errorHandler instanceof PageErrorHandlerInterface) {
+        if ($errorHandler !== null) {
             return $errorHandler->handlePageError($request, $message, $reasons);
         }
         try {
diff --git a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
index 74f6573eea97..dd2ee67f000a 100644
--- a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
@@ -62,7 +62,7 @@ class BackendUserAuthenticator extends \TYPO3\CMS\Core\Middleware\BackendUserAut
         // Load specific dependencies which are necessary for a valid Backend User
         // like $GLOBALS['LANG'] for labels in the language of the BE User, the router, and ext_tables.php for all modules
         // So things like Frontend Editing and Admin Panel can use this for generating links to the TYPO3 Backend.
-        if ($backendUserObject instanceof FrontendBackendUserAuthentication) {
+        if ($backendUserObject !== null) {
             $GLOBALS['LANG'] = $this->languageServiceFactory->createFromUserPreferences($GLOBALS['BE_USER']);
             Bootstrap::loadExtTables();
             $this->setBackendUserAspect($GLOBALS['BE_USER']);
diff --git a/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php b/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php
index 8ef8051b304b..41a66db9ec88 100644
--- a/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php
+++ b/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php
@@ -96,7 +96,7 @@ class SiteBaseRedirectResolver implements MiddlewareInterface
     protected function isLanguageEnabled(SiteLanguage $language, ?BackendUserAuthentication $user = null): bool
     {
         // language is hidden, check if a possible backend user is allowed to access the language
-        if ($language->enabled() || ($user instanceof BackendUserAuthentication && $user->checkLanguageAccess($language->getLanguageId()))) {
+        if ($language->enabled() || $user?->checkLanguageAccess($language->getLanguageId())) {
             return true;
         }
         return false;
diff --git a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
index 3ce819c484f6..37dfaef20214 100644
--- a/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
+++ b/typo3/sysext/frontend/Classes/Typolink/PageLinkBuilder.php
@@ -466,15 +466,10 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
     protected function getSiteLanguageOfTargetPage(Site $siteOfTargetPage, string $targetLanguageId): SiteLanguage
     {
         $currentSite = $this->getCurrentSite();
-        $currentSiteLanguage = $this->getCurrentSiteLanguage();
-        // Happens when currently on a pseudo-site configuration
-        // We assume to use the default language then
-        if ($currentSite && !($currentSiteLanguage instanceof SiteLanguage)) {
-            $currentSiteLanguage = $currentSite->getDefaultLanguage();
-        }
+        $currentSiteLanguage = $this->getCurrentSiteLanguage() ?? $currentSite?->getDefaultLanguage();
 
         if ($targetLanguageId === 'current') {
-            $targetLanguageId = $currentSiteLanguage ? $currentSiteLanguage->getLanguageId() : 0;
+            $targetLanguageId = $currentSiteLanguage?->getLanguageId() ?? 0;
         } else {
             $targetLanguageId = (int)$targetLanguageId;
         }
@@ -495,12 +490,7 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
     {
         $tsfe = $this->getTypoScriptFrontendController();
         $currentSite = $this->getCurrentSite();
-        $currentSiteLanguage = $this->getCurrentSiteLanguage();
-        // Happens when currently on a pseudo-site configuration
-        // We assume to use the default language then
-        if ($currentSite && !($currentSiteLanguage instanceof SiteLanguage)) {
-            $currentSiteLanguage = $currentSite->getDefaultLanguage();
-        }
+        $currentSiteLanguage = $this->getCurrentSiteLanguage() ?? $currentSite?->getDefaultLanguage();
 
         $siteLanguageOfTargetPage = $this->getSiteLanguageOfTargetPage($siteOfTargetPage, (string)($conf['language'] ?? 'current'));
 
@@ -517,7 +507,7 @@ class PageLinkBuilder extends AbstractTypolinkBuilder
         if (
             !$currentSite
             || $currentSite->getRootPageId() !== $siteOfTargetPage->getRootPageId()
-            || $siteLanguageOfTargetPage->getBase()->getHost() !== $currentSiteLanguage->getBase()->getHost()) {
+            || $siteLanguageOfTargetPage->getBase()->getHost() !== $currentSiteLanguage?->getBase()?->getHost()) {
             $useAbsoluteUrl = true;
         }
 
diff --git a/typo3/sysext/impexp/Classes/Controller/ExportController.php b/typo3/sysext/impexp/Classes/Controller/ExportController.php
index 71bfb278dbc8..1d5038fdf615 100644
--- a/typo3/sysext/impexp/Classes/Controller/ExportController.php
+++ b/typo3/sysext/impexp/Classes/Controller/ExportController.php
@@ -125,7 +125,7 @@ class ExportController
             return $this->getDownload($export);
         }
         $saveFolder = $export->getOrCreateDefaultImportExportFolder();
-        if (($inputData['save_export'] ?? false) && ($saveFolder instanceof Folder)) {
+        if (($inputData['save_export'] ?? false) && $saveFolder !== null) {
             $this->saveExportToFile($view, $export, $saveFolder);
         }
         $inputData['filename'] = $export->getExportFileName();
@@ -144,7 +144,7 @@ class ExportController
             'presetSelectOptions' => $this->presetRepository->getPresets($id),
             'fileName' => '',
             'filetypeSelectOptions' => $this->getFileSelectOptions($export),
-            'saveFolder' => ($saveFolder instanceof Folder) ? $saveFolder->getPublicUrl() : '',
+            'saveFolder' => $saveFolder?->getPublicUrl() ?? '',
             'hasSaveFolder' => true,
             'extensions' => $this->getExtensionList(),
             'inData' => $inputData,
diff --git a/typo3/sysext/impexp/Classes/Controller/ImportController.php b/typo3/sysext/impexp/Classes/Controller/ImportController.php
index 9e320d33febd..ac4f5b4b3fbd 100644
--- a/typo3/sysext/impexp/Classes/Controller/ImportController.php
+++ b/typo3/sysext/impexp/Classes/Controller/ImportController.php
@@ -32,7 +32,6 @@ use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
-use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
@@ -102,7 +101,7 @@ class ImportController
         if ($request->getMethod() === 'POST' && isset($parsedBody['_upload'])) {
             $uploadStatus = self::UPLOAD_FAILED;
             $file = $this->handleFileUpload($request);
-            if (($file instanceof File) && in_array($file->getExtension(), ['t3d', 'xml'], true)) {
+            if ($file !== null && in_array($file->getExtension(), ['t3d', 'xml'], true)) {
                 $inputData['file'] = $file->getCombinedIdentifier();
                 $uploadStatus = self::UPLOAD_DONE;
                 $uploadedFileName = $file->getName();
@@ -113,7 +112,7 @@ class ImportController
         $importFolder = $import->getOrCreateDefaultImportExportFolder();
 
         $view->assignMultiple([
-            'importFolder' => ($importFolder instanceof Folder) ? $importFolder->getCombinedIdentifier() : '',
+            'importFolder' => $importFolder?->getCombinedIdentifier() ?? '',
             'import' => $import,
             'errors' => $import->getErrorLog(),
             'preview' => $import->renderPreview(),
diff --git a/typo3/sysext/impexp/Classes/Export.php b/typo3/sysext/impexp/Classes/Export.php
index a079a1418f43..215b8553c086 100644
--- a/typo3/sysext/impexp/Classes/Export.php
+++ b/typo3/sysext/impexp/Classes/Export.php
@@ -1318,7 +1318,7 @@ class Export extends ImportExport
         $filesFolderName = $fileName . '.files';
         $fileContent = $this->render();
 
-        if (!($saveFolder instanceof Folder && $saveFolder->checkActionPermission('write'))) {
+        if (!($saveFolder?->checkActionPermission('write'))) {
             throw new InsufficientFolderWritePermissionsException(
                 'You are not allowed to write to the target folder "' . $saveFolder->getPublicUrl() . '"',
                 1602432207
diff --git a/typo3/sysext/install/Classes/Middleware/Maintenance.php b/typo3/sysext/install/Classes/Middleware/Maintenance.php
index 0dc657fcc699..75ce9ee9354c 100644
--- a/typo3/sysext/install/Classes/Middleware/Maintenance.php
+++ b/typo3/sysext/install/Classes/Middleware/Maintenance.php
@@ -200,7 +200,7 @@ class Maintenance implements MiddlewareInterface
             ]);
         } else {
             $enforceReferrerResponse = $this->enforceReferrer($request);
-            if ($enforceReferrerResponse instanceof ResponseInterface) {
+            if ($enforceReferrerResponse !== null) {
                 return $enforceReferrerResponse;
             }
             $session->initializeSession();
diff --git a/typo3/sysext/redirects/Classes/Hooks/DataHandlerSlugUpdateHook.php b/typo3/sysext/redirects/Classes/Hooks/DataHandlerSlugUpdateHook.php
index dcf2bc5e5882..a15b4cac4d60 100644
--- a/typo3/sysext/redirects/Classes/Hooks/DataHandlerSlugUpdateHook.php
+++ b/typo3/sysext/redirects/Classes/Hooks/DataHandlerSlugUpdateHook.php
@@ -60,9 +60,10 @@ class DataHandlerSlugUpdateHook
         }
 
         $changeItem = $this->slugRedirectChangeItemFactory->create((int)$id);
-        if ($changeItem instanceof SlugRedirectChangeItem) {
-            $this->persistedChangedItems[(int)$id] = $changeItem;
+        if ($changeItem === null) {
+            return;
         }
+        $this->persistedChangedItems[(int)$id] = $changeItem;
     }
 
     /**
@@ -79,8 +80,7 @@ class DataHandlerSlugUpdateHook
             $table !== 'pages'
             || $status !== 'update'
             || empty($fieldArray['slug'])
-            || !($persistedChangedItem instanceof SlugRedirectChangeItem)
-            || $persistedChangedItem->getOriginal()['slug'] === $fieldArray['slug']
+            || $persistedChangedItem?->getOriginal()['slug'] === $fieldArray['slug']
             || $this->isNestedHookInvocation($dataHandler)
         ) {
             return;
diff --git a/typo3/sysext/redirects/Classes/Http/Middleware/RedirectHandler.php b/typo3/sysext/redirects/Classes/Http/Middleware/RedirectHandler.php
index 184bc014b33c..04d0b8ddc551 100644
--- a/typo3/sysext/redirects/Classes/Http/Middleware/RedirectHandler.php
+++ b/typo3/sysext/redirects/Classes/Http/Middleware/RedirectHandler.php
@@ -64,32 +64,32 @@ class RedirectHandler implements MiddlewareInterface
         );
 
         // If the matched redirect is found, resolve it, and check further
-        if (is_array($matchedRedirect)) {
-            $url = $this->redirectService->getTargetUrl($matchedRedirect, $request);
-            if ($url instanceof UriInterface) {
-                if ($this->redirectUriWillRedirectToCurrentUri($request, $url)) {
-                    if ($this->isEmptyRedirectUri($url)) {
-                        // Empty uri leads to a redirect loop in Firefox, whereas Chrome would stop it but not displaying anything.
-                        // @see https://forge.typo3.org/issues/100791
-                        $this->logger->error('Empty redirect points to itself! Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
-                    } elseif ($url->getFragment()) {
-                        // Enrich error message for unsharp check with target url fragment.
-                        $this->logger->error('Redirect ' . $url->getPath() . ' eventually points to itself! Target with fragment can not be checked and we take the safe check to avoid redirect loops. Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
-                    } else {
-                        $this->logger->error('Redirect ' . $url->getPath() . ' points to itself! Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
-                    }
-                    return $handler->handle($request);
-                }
-                $this->logger->debug('Redirecting', ['record' => $matchedRedirect, 'uri' => (string)$url]);
-                $response = $this->buildRedirectResponse($url, $matchedRedirect);
-                // Dispatch event, allowing listeners to execute further tasks and to adjust the PSR-7 response
-                return $this->eventDispatcher->dispatch(
-                    new RedirectWasHitEvent($request, $response, $matchedRedirect, $url)
-                )->getResponse();
+        if (!is_array($matchedRedirect)) {
+            return $handler->handle($request);
+        }
+        $url = $this->redirectService->getTargetUrl($matchedRedirect, $request);
+        if ($url === null) {
+            return $handler->handle($request);
+        }
+        if ($this->redirectUriWillRedirectToCurrentUri($request, $url)) {
+            if ($this->isEmptyRedirectUri($url)) {
+                // Empty uri leads to a redirect loop in Firefox, whereas Chrome would stop it but not displaying anything.
+                // @see https://forge.typo3.org/issues/100791
+                $this->logger->error('Empty redirect points to itself! Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
+            } elseif ($url->getFragment()) {
+                // Enrich error message for unsharp check with target url fragment.
+                $this->logger->error('Redirect ' . $url->getPath() . ' eventually points to itself! Target with fragment can not be checked and we take the safe check to avoid redirect loops. Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
+            } else {
+                $this->logger->error('Redirect ' . $url->getPath() . ' points to itself! Aborting.', ['record' => $matchedRedirect, 'uri' => (string)$url]);
             }
+            return $handler->handle($request);
         }
-
-        return $handler->handle($request);
+        $this->logger->debug('Redirecting', ['record' => $matchedRedirect, 'uri' => (string)$url]);
+        $response = $this->buildRedirectResponse($url, $matchedRedirect);
+        // Dispatch event, allowing listeners to execute further tasks and to adjust the PSR-7 response
+        return $this->eventDispatcher->dispatch(
+            new RedirectWasHitEvent($request, $response, $matchedRedirect, $url)
+        )->getResponse();
     }
 
     protected function buildRedirectResponse(UriInterface $uri, array $redirectRecord): ResponseInterface
diff --git a/typo3/sysext/scheduler/Classes/Scheduler.php b/typo3/sysext/scheduler/Classes/Scheduler.php
index 6ecf13f82737..5f91a82a69f2 100644
--- a/typo3/sysext/scheduler/Classes/Scheduler.php
+++ b/typo3/sysext/scheduler/Classes/Scheduler.php
@@ -194,7 +194,7 @@ class Scheduler implements SingletonInterface
             ]);
             // Now that the result of the task execution has been handled,
             // throw the exception again, if any
-            if ($e instanceof \Throwable) {
+            if ($e !== null) {
                 throw $e;
             }
         }
diff --git a/typo3/sysext/tstemplate/Classes/Controller/TemplateAnalyzerController.php b/typo3/sysext/tstemplate/Classes/Controller/TemplateAnalyzerController.php
index 739302aebd33..8b00f8e54f3e 100644
--- a/typo3/sysext/tstemplate/Classes/Controller/TemplateAnalyzerController.php
+++ b/typo3/sysext/tstemplate/Classes/Controller/TemplateAnalyzerController.php
@@ -27,7 +27,6 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Http\RedirectResponse;
-use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\IncludeInterface;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\IncludeNode\RootInclude;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateTreeBuilder;
@@ -40,7 +39,6 @@ use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeNodeFinderVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSetupConditionConstantSubstitutionVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSourceAggregatorVisitor;
 use TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSyntaxScannerVisitor;
-use TYPO3\CMS\Core\TypoScript\Tokenizer\Line\LineStream;
 use TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\RootlineUtility;
@@ -197,12 +195,7 @@ final class TemplateAnalyzerController extends AbstractTemplateModuleController
         $nodeFinderVisitor->setNodeIdentifier($includeIdentifier);
         $this->treeTraverser->traverse($includeTree, [$nodeFinderVisitor]);
         $foundNode = $nodeFinderVisitor->getFoundNode();
-
-        if (!$foundNode instanceof IncludeInterface) {
-            return $this->responseFactory->createResponse(400);
-        }
-        $lineStream = $foundNode->getLineStream();
-        if (!$lineStream instanceof LineStream) {
+        if ($foundNode?->getLineStream() === null) {
             return $this->responseFactory->createResponse(400);
         }
 
diff --git a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
index cc609d29b4f5..47b100170501 100644
--- a/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
+++ b/typo3/sysext/workspaces/Classes/Middleware/WorkspacePreview.php
@@ -99,7 +99,7 @@ class WorkspacePreview implements MiddlewareInterface
             $previewWorkspaceId = (int)$this->getWorkspaceIdFromRequest($keyword);
             if ($previewWorkspaceId > 0 && $routeResult instanceof RouteResultInterface) {
                 $previewUser = $this->initializePreviewUser($previewWorkspaceId);
-                if ($previewUser instanceof PreviewUserAuthentication) {
+                if ($previewUser !== null) {
                     $GLOBALS['BE_USER'] = $previewUser;
                     // Register the preview user as aspect
                     $this->setBackendUserAspect($context, $previewUser);
@@ -127,12 +127,12 @@ class WorkspacePreview implements MiddlewareInterface
         $response = $handler->handle($request);
 
         $tsfe = $this->getTypoScriptFrontendController();
-        if ($tsfe instanceof TypoScriptFrontendController && $addInformationAboutDisabledCache) {
+        if ($tsfe !== null && $addInformationAboutDisabledCache) {
             $tsfe->set_no_cache('GET Parameter ADMCMD_prev=LIVE was given', true);
         }
 
         // Add an info box to the frontend content
-        if ($tsfe instanceof TypoScriptFrontendController && $context->getPropertyFromAspect('workspace', 'isOffline', false)) {
+        if ($tsfe !== null && $context->getPropertyFromAspect('workspace', 'isOffline', false)) {
             $previewInfo = $this->renderPreviewInfo($tsfe, $request->getUri());
             $body = $response->getBody();
             $body->rewind();
-- 
GitLab