The Reader Component
Edit pageLast modified: 10 October 2024This package provides a set of methods for reading PHP metadata and converting it into the TypeLang AST Nodes.
Installation
Via Composer: composer require type-lang/reader
Requirements:
PHP >= 8.1
Usage
Package supports two reader classes.
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
{...}
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
{...}
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
{...}
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
{...}
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
{...}
$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
{...}
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
{...}
$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
{...}
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.
tip
The
type-lang/printer
component is used to print the types.
$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),
]);
}
}
}