PHP TypeLang Help

The Reader Component

This package provides a set of methods for reading PHP metadata and converting it into the TypeLang AST Nodes.

Installation

Requirements:

  • PHP >= 8.1

Usage

Package supports two reader classes.

TypeLang\Reader\ReflectionReader

Used to read types metadata from reflection objects.

TypeLang\Reader\AttributeReader

Used to read types metadata from attributes.

Any reader implements the TypeLang\Reader\ReaderInterface interface, which contains several methods:

Constants

Method findConstantType() is used to read types from constants.

class Example { public const int EXAMPLE = 0xDEAD_BEEF; } $reader = new \TypeLang\Reader\ReflectionReader(); $result = $reader->findConstantType( constant: new \ReflectionClassConstant( class: Example::class, constant: 'EXAMPLE', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "int" } ] } +arguments: null +fields: null }
class Example { #[TypeLang\Reader\Attribute\MapType('int<0, max>')] public const int EXAMPLE = 0xDEAD_BEEF; } $reader = new \TypeLang\Reader\AttributeReader(); $result = $reader->findConstantType( constant: new \ReflectionClassConstant( class: Example::class, constant: 'EXAMPLE', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 +parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "int" } ] } +arguments: TypeLang\Parser\Node\Stmt\Template\TemplateArgumentsListNode { +offset: 3 +items: array:2 [ 0 => TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode { +offset: 4 +hint: null +value: TypeLang\Parser\Node\Literal\IntLiteralNode {#798 +offset: 4 +raw: "0" +value: 0 } +attributes: null } 1 => TypeLang\Parser\Node\Stmt\Template\TemplateArgumentNode { +offset: 7 +hint: null +value: TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 7 +name: TypeLang\Parser\Node\Name { +offset: 7 +parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 7 +value: "max" } ] } +arguments: null +fields: null } +attributes: null } ] } +fields: null }

Properties

Method findPropertyType() is used to read types from class properties.

class Example { public readonly string $test; } $reader = new \TypeLang\Reader\ReflectionReader(); $result = $reader->findPropertyType( property: new \ReflectionProperty( class: Example::class, property: 'test', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "string" } ] } +arguments: null +fields: null }
class Example { #[TypeLang\Reader\Attribute\MapType('non-empty-string')] public readonly string $test; } $reader = new \TypeLang\Reader\AttributeReader(); $result = $reader->findPropertyType( property: new \ReflectionProperty( class: Example::class, property: 'test', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 +parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "non-empty-string" } ] } +arguments: null +fields: null }

Functions

Method findFunctionType() is used to read return types from functions and class methods.

$example = function(): void {}; $reader = new \TypeLang\Reader\ReflectionReader(); $result = $reader->findFunctionType( function: new \ReflectionFunction($example), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "void" } ] } +arguments: null +fields: null }
$example = #[TypeLang\Reader\Attribute\MapType('never')] function(): void {}; $reader = new \TypeLang\Reader\AttributeReader(); $result = $reader->findFunctionType( function: new \ReflectionFunction($example), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "never" } ] } +arguments: null +fields: null }

Parameters

Method findParameterType() is used to read types from function and method parameters.

$example = function(bool $param) {}; $reader = new \TypeLang\Reader\ReflectionReader(); $result = $reader->findParameterType( parameter: new \ReflectionParameter( function: $example, param: 'param', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "bool" } ] } +arguments: null +fields: null }
$example = function( #[TypeLang\Reader\Attribute\MapType('true')] bool $param, ) {}; $reader = new \TypeLang\Reader\AttributeReader(); $result = $reader->findParameterType( parameter: new \ReflectionParameter( function: $example, param: 'param', ), );
TypeLang\Parser\Node\Stmt\NamedTypeNode { +offset: 0 +name: TypeLang\Parser\Node\Name { +offset: 0 -parts: array:1 [ 0 => TypeLang\Parser\Node\Identifier { +offset: 0 +value: "true" } ] } +arguments: null +fields: null }

Attribute Reader

The TypeLang\Reader\AttributeReader provides the ability to modify its behavior. To do this, you should pass the TypeLang\Reader\AttributeReader\AttributeProviderInterface implementation to the constructor of this class.

use TypeLang\Reader\AttributeReader; use TypeLang\Reader\AttributeReader\AttributeProviderInterface; $reader = new AttributeReader( provider: new class implements AttributeProviderInterface { public function getAttribute(): string { // // The class of the attribute to be // read should be returned. // return AttributeClassName::class; } public function getTypeFromAttribute( object $attribute, ): string { // // A value with a type description from // the attribute should be returned. // return $attribute->propertyWithTypeDefinition; } public function process( object $attribute, TypeStatement $statement, ): TypeStatement { // // You can also modify the return type based // on information from the attribute. // return $statement; } }, );

Complex Example

Complete example for reading and printing types from an entire class.

$class = new \ReflectionClass(Path\To\Example::class); $printer = new \TypeLang\Printer\PrettyPrinter(); $converter = new \TypeLang\Reader\ReflectionReader(); // Dump all constants with its types. foreach ($class->getReflectionConstants() as $constant) { // Creates type node AST from a constant's type. if ($type = $converter->findConstantType($constant)) { echo vsprintf("const %s has type %s\n", [ $constant->name, $printer->print($type), ]); } } // Dump all properties with its types. foreach ($class->getProperties() as $property) { // Creates type node AST from a property's type. if ($type = $converter->findPropertyType($property)) { echo vsprintf("property %s has type %s\n", [ $property->name, $printer->print($type), ]); } } // Dump all methods with its types. foreach ($class->getMethods() as $method) { // Creates type node AST from any function's return type. if ($type = $converter->findFunctionType($method)) { echo vsprintf("function %s has type %s\n", [ $method->name, $printer->print($type), ]); } // Creates type node AST from a parameter's type. foreach ($method->getParameters() as $parameter) { if ($type = $converter->findParameterType($parameter)) { echo vsprintf("parameter %s has type %s\n", [ $parameter->name, $printer->print($type), ]); } } }
03 February 2025