VOOZH about

URL: https://deepwiki.com/MahoCommerce/maho-phpstan-plugin/4-type-inference-system

⇱ Type Inference System | MahoCommerce/maho-phpstan-plugin | DeepWiki


Loading...
Menu

Type Inference System

This document explains how the plugin resolves Magento factory method return types to enable static analysis of dynamic factory patterns. The type inference system is the core functionality that allows PHPStan to understand methods like Mage::getModel('catalog/product') and infer that they return specific model classes.

For detailed documentation of individual components, see:

For information about reflection extensions (magic methods and template scope), see Reflection Extensions.

Problem Statement

Maho/Magento uses a factory pattern where class instances are created through factory methods that accept string aliases rather than class names:


Without type inference, PHPStan cannot determine the return type of these factory methods, resulting in mixed types that prevent proper static analysis. The type inference system resolves these string aliases to concrete class names at analysis time.

Sources: src/Type/MageTypeExtension.php1-90

Architecture Overview

The type inference system consists of three primary components working in a two-phase pipeline:


Component Responsibilities:

ComponentRoleExtension Type
MageTypeExtensionIntercepts factory method calls and infers return typesDynamicStaticMethodReturnTypeExtension
DynamicMethodReturnTypeExtension
MageCoreConfigProvides converter functions and manages Mage initializationService (injected)
MageInvalidTypeRuleValidates that resolved types exist and reports errorsRule<Node\Expr\CallLike>

Sources: src/Type/MageTypeExtension.php1-90 src/Config/MageCoreConfig.php1-76 src/Rules/MageInvalidTypeRule.php1-97

Type Resolution Flow

Method Call Detection

When PHPStan encounters a method call, MageTypeExtension determines if it should handle the call:


The isMethodSupported() method checks whether a converter function exists for the method being called by consulting MageCoreConfig.

Sources: src/Type/MageTypeExtension.php37-45 src/Config/MageCoreConfig.php34-74

Alias to Class Name Resolution

When a supported method is called, MageTypeExtension extracts the alias from the first argument and resolves it to a class name:


The resolution process at src/Type/MageTypeExtension.php47-79:

  1. Extract alias: $scope->getType($methodCall->getArgs()[0]->value)->getConstantStrings()
  2. Get converter: $mageCoreConfig->getClassNameConverterFunction(className, methodName)
  3. Resolve class name: $fn($alias->getValue())
  4. Validate existence: class_exists($className)
  5. Build type: new ObjectType($className) or new ConstantBooleanType(false)

Sources: src/Type/MageTypeExtension.php47-79 src/Config/MageCoreConfig.php34-74

Supported Factory Methods

MageCoreConfig provides converters for multiple factory patterns through a match expression at src/Config/MageCoreConfig.php36-73:


Each converter function returns either a class name string or false if resolution fails.

Sources: src/Config/MageCoreConfig.php34-74

Configuration and Initialization

Mage Framework Initialization

MageCoreConfig manages initialization of the mock Mage framework at src/Config/MageCoreConfig.php18-29:


The initialization happens lazily on first use to avoid unnecessary overhead. The useLocalXml parameter (configured in extension.neon) controls whether to initialize the Mage framework.

Sources: src/Config/MageCoreConfig.php13-29

Parameter Configuration

The useLocalXml parameter is injected through extension.neon:


Sources: src/Config/MageCoreConfig.php10-16

Type Validation

After type inference, MageInvalidTypeRule validates the resolved types at src/Rules/MageInvalidTypeRule.php32-95:


The rule processes the same method calls as MageTypeExtension but focuses on validation rather than type inference. It reports errors when:

  • The converter returns false (resolved to bool(false))
  • The converter returns a string that doesn't correspond to an existing class

Sources: src/Rules/MageInvalidTypeRule.php32-95

Union Types and Multiple Aliases

The type inference system handles cases where the alias argument could be one of multiple constant strings:


At src/Type/MageTypeExtension.php62-78 the extension:

  1. Extracts all constant strings from the argument type: $scope->getType($methodCall->getArgs()[0]->value)->getConstantStrings()
  2. Resolves each alias to a class name
  3. Creates an ObjectType for each valid class or ConstantBooleanType(false) for invalid ones
  4. Combines all types using TypeCombinator::union()

Sources: src/Type/MageTypeExtension.php62-78

Integration with PHPStan Extension System

The type inference components are registered in extension.neon with specific PHPStan service tags:


Multiple MageTypeExtension instances are registered for different classes (Mage, Mage_Core_Model_Factory, Mage_Core_Model_Layout, Mage_Core_Block_Abstract), each configured with the appropriate class name. All instances share the same MageCoreConfig service through dependency injection.

Sources: src/Type/MageTypeExtension.php20-35 src/Rules/MageInvalidTypeRule.php21-25

Complete Data Flow Example

This diagram shows the complete flow when PHPStan analyzes Mage::getModel('catalog/product'):


Sources: src/Type/MageTypeExtension.php47-89 src/Config/MageCoreConfig.php18-29 src/Config/MageCoreConfig.php34-74 src/Rules/MageInvalidTypeRule.php32-95