VOOZH about

URL: https://deepwiki.com/MahoCommerce/maho-phpstan-plugin/5-reflection-extensions

⇱ Reflection Extensions | MahoCommerce/maho-phpstan-plugin | DeepWiki


Loading...
Menu

Reflection Extensions

The Reflection Extensions subsystem provides PHPStan with enhanced understanding of Maho/Magento's dynamic reflection patterns. This system addresses two primary analysis challenges: magic method support on Varien_Object descendants and visibility override requirements in .phtml template files and data installation scripts.

For detailed information on specific components, see:

System Overview

The reflection system consists of three integrated components registered as PHPStan extensions in extension.neon:

ComponentPHPStan Extension TypePrimary Purpose
VarienObjectReflectionExtensionMethodsClassReflectionExtensionIntercepts and resolves magic method calls (e.g., getFoo(), setBar())
BindThisScopeResolverExtensionTypeNodeResolverExtension, NodeVisitorAbstractTransforms @var Type $this annotations into special scope-aware types
PublicMethodReflectionWrapper classForces protected/private methods to appear public
PublicPropertyReflectionWrapper classForces protected/private properties to appear public

These components work together to bridge the gap between Maho's runtime behavior and PHPStan's static analysis model.

Sources: src/Reflection/VarienObjectReflectionExtension.php1-76 src/PhpDoc/BindThisScopeResolverExtension.php1-90 src/Reflection/PublicMethodReflection.php1-176

Architecture


Sources: src/Reflection/VarienObjectReflectionExtension.php14-75 src/PhpDoc/BindThisScopeResolverExtension.php25-89 src/Reflection/PublicMethodReflection.php23-175

Magic Method Resolution Flow

When PHPStan encounters a method call on a Varien_Object or Maho\DataObject descendant that doesn't exist in the class definition, the following resolution process occurs:


The hasMethod() implementation in src/Reflection/VarienObjectReflectionExtension.php26-61 performs several checks:

  1. Prefix validation: Method name must start with get, set, uns, or has
  2. Class hierarchy check: Must be subclass of Varien_Object or Maho\DataObject
  3. Tag exclusion: Must not have explicit @method tag defined
  4. DocBlock enforcement: Optional strict mode requiring explicit documentation

Sources: src/Reflection/VarienObjectReflectionExtension.php26-74

Template Scope Resolution Flow

The BindThisScopeResolverExtension operates in two phases: AST transformation during parsing and type resolution during analysis.


The transformation pattern is defined in src/PhpDoc/BindThisScopeResolverExtension.php28-29:

Pattern: /@var\s+((\\\?\w+)+)\s+\$this/
Replace: @var bind-this-scope<$1> $this

This transforms annotations like @var Mage_Catalog_Block_Product $this into @var bind-this-scope<Mage_Catalog_Block_Product> $this, which is then resolved to a custom type.

Sources: src/PhpDoc/BindThisScopeResolverExtension.php31-89

The bind-this-scope Generic Type

The bind-this-scope<T> pseudo-generic type is a custom PHPStan type created by an anonymous class in src/PhpDoc/BindThisScopeResolverExtension.php72-87 This anonymous class extends ObjectType and overrides three critical methods:

MethodOverride Behavior
getMethod()Wraps result in PublicMethodReflection
getProperty()Wraps result in PublicPropertyReflection
getInstanceProperty()Wraps result in PublicPropertyReflection

This ensures that any method or property access on the $this variable in template contexts appears to have public visibility, regardless of its actual declared visibility.

Example Transformation

Original Template Code:


After AST Transformation:


Sources: src/PhpDoc/BindThisScopeResolverExtension.php72-87

Visibility Override Wrappers

The PublicMethodReflection and PublicPropertyReflection classes implement the Decorator pattern to wrap existing reflection objects and override visibility checks.

PublicMethodReflection

This wrapper implements ExtendedMethodReflection and delegates all method calls to the original reflection object, except for visibility methods:


Key implementation details from src/Reflection/PublicMethodReflection.php39-46:

  • isPrivate() always returns false
  • isPublic() always returns true
  • All other methods delegate to the wrapped $originalMethod

PublicPropertyReflection

Similar to PublicMethodReflection, this wrapper implements ExtendedPropertyReflection and overrides visibility methods while delegating all other operations.

Sources: src/Reflection/PublicMethodReflection.php14-175 src/Reflection/PublicPropertyReflection.php1

Extension Registration

The reflection extensions are registered in extension.neon with the following service definitions:


The VarienObjectReflectionExtension receives the enforceMagicMethodDocBlock parameter, which controls whether magic methods require explicit @method tags in docblocks. The BindThisScopeResolverExtension is registered with two tags:

  1. phpstan.parser.richParserNodeVisitor - enables AST transformation during parsing
  2. phpstan.phpDoc.typeNodeResolverExtension - enables custom type resolution

Sources: extension.neon1

Configuration Parameters

ParameterTypeDefaultPurpose
enforceMagicMethodDocBlockboolfalseWhen true, requires explicit @method tags for magic methods on Varien_Object subclasses

This parameter is defined in extension.neon and injected into VarienObjectReflectionExtension via constructor injection in src/Reflection/VarienObjectReflectionExtension.php22-24

Sources: extension.neon1 src/Reflection/VarienObjectReflectionExtension.php22-24

Supported Base Classes

The VarienObjectReflectionExtension supports magic methods for classes that extend either:

  • Varien_Object (Magento 1.x style)
  • Maho\DataObject (Maho/Magento 2.x style)

These are defined as constants in src/Reflection/VarienObjectReflectionExtension.php16-20:


Sources: src/Reflection/VarienObjectReflectionExtension.php16-20

PHPStan API Stability Note

Both wrapper classes (PublicMethodReflection and PublicPropertyReflection) implement PHPStan interfaces that are explicitly not covered by PHPStan's backward compatibility promise:

  • ExtendedMethodReflection
  • ExtendedPropertyReflection

These classes include a @phpstan-ignore phpstanApi.interface annotation to suppress warnings about using unstable APIs. This is documented in src/Reflection/PublicMethodReflection.php14-22 as an accepted trade-off for extension development.

Sources: src/Reflection/PublicMethodReflection.php14-22