Skip to content

Commit

Permalink
Add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
vudaltsov committed Oct 2, 2024
1 parent f51755a commit 6d6cbd0
Show file tree
Hide file tree
Showing 6 changed files with 460 additions and 2 deletions.
64 changes: 62 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,68 @@
[![Code Coverage](https://codecov.io/gh/typhoon-php/reflection/branch/0.4.x/graph/badge.svg)](https://codecov.io/gh/typhoon-php/reflection/tree/0.4.x)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Ftyphoon-php%2Freflection%2F0.4.x)](https://dashboard.stryker-mutator.io/reports/github.com/typhoon-php/reflection/0.4.x)

Typhoon Reflection is an alternative to [native PHP Reflection](https://www.php.net/manual/en/book.reflection.php). It
is:

- static (does not run or autoload reflected code),
- fast (due to lazy loading and caching),
- [fully compatible with native reflection](reflection/native_adapters.md),
- supports most of the Psalm and PHPStan phpDoc types,
- can resolve templates,
- does not leak memory and can be safely used
with [zend.enable_gc=0](https://www.php.net/manual/en/info.configuration.php#ini.zend.enable-gc).

## Installation

```shell
composer require typhoon/reflection
```
composer require typhoon/reflection typhoon/phpstorm-reflection-stubs
```

`typhoon/phpstorm-reflection-stubs` is a bridge for `jetbrains/phpstorm-stubs`. Without this package internal classes
and functions are reflected from native reflection without templates.

## Basic Usage

```php
use Typhoon\Reflection\TyphoonReflector;
use Typhoon\Type\types;
use function Typhoon\Type\stringify;

/**
* @template TTag of non-empty-string
*/
final readonly class Article
{
/**
* @param list<TTag> $tags
*/
public function __construct(
private array $tags,
) {}
}

$reflector = TyphoonReflector::build();
$class = $reflector->reflectClass(Article::class);
$tagsType = $class->properties()['tags']->type();

var_dump(stringify($tagsType)); // "list<TTag#Article>"

$templateResolver = $class->createTemplateResolver([
types::union(
types::string('PHP'),
types::string('Architecture'),
),
]);

var_dump(stringify($tagsType->accept($templateResolver))); // "list<'PHP'|'Architecture'>"
```

## Documentation

- [Native reflection adapters](docs/native_adapters.md)
- [Reflecting Types](docs/types.md)
- [Reflecting PHPDoc properties and methods](docs/php_doc_properties_and_methods.md)
- [Implementing custom types](docs/implementing_custom_types.md)
- [Caching](docs/caching.md)

Documentation is still far from being complete. Don't hesitate to create issues to clarify how things work.
28 changes: 28 additions & 0 deletions docs/caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Caching

By default, Typhoon Reflection uses in-memory LRU cache which should be enough for the majority of use cases.

However, if you need persistent cache, you can use any [PSR-16](https://www.php-fig.org/psr/psr-16/) implementation. We
highly recommend [Typhoon OPcache](https://github.com/typhoon-php/opcache). It stores values as opcacheable php files.

```php
use Typhoon\Reflection\TyphoonReflector;
use Typhoon\OPcache\TyphoonOPcache;

$reflector = TyphoonReflector::build(
cache: new TyphoonOPcache('path/to/cache/dir'),
);
```

To detect file changes during development, decorate your cache
with [FreshCache](../../src/Reflection/Cache/FreshCache.php).

```php
use Typhoon\Reflection\TyphoonReflector;
use Typhoon\Reflection\Cache\FreshCache;
use Typhoon\OPcache\TyphoonOPcache;

$reflector = TyphoonReflector::build(
cache: new FreshCache(new TyphoonOPcache('path/to/cache/dir')),
);
```
62 changes: 62 additions & 0 deletions docs/implementing_custom_types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Implementing custom types

```php
use Typhoon\Reflection\Annotated\CustomTypeResolver;
use Typhoon\Reflection\Annotated\TypeContext;
use Typhoon\Reflection\TyphoonReflector;
use Typhoon\Type\Type;
use Typhoon\Type\types;
use Typhoon\Type\TypeVisitor;
use function Typhoon\Type\stringify;

/**
* @implements Type<int|float>
*/
enum binary: string implements Type, CustomTypeResolver
{
case int16 = 'int16';
case int32 = 'int32';
case int64 = 'int64';
case float32 = 'float32';
case float64 = 'float64';

public function accept(TypeVisitor $visitor): mixed
{
/**
* We need to suppress here, because Psalm does not support var annotations on enum cases yet ;(
* @psalm-suppress InvalidArgument
*/
return match ($this) {
self::int16 => $visitor->int($this, types::int(-32768), types::int(32767)),
self::int32 => $visitor->int($this, types::int(-2147483648), types::int(2147483647)),
self::int64 => $visitor->int($this, types::PHP_INT_MIN, types::PHP_INT_MAX),
self::float32 => $visitor->float($this, types::float(-3.40282347E+38), types::float(3.40282347E+38)),
self::float64 => $visitor->float($this, types::PHP_FLOAT_MIN, types::PHP_FLOAT_MAX),
};
}

public function resolveCustomType(string $name, array $typeArguments, TypeContext $context): ?Type
{
return self::tryFrom($name);
}
}

final readonly class Message
{
/**
* @param list<int16> $some16bitIntegers
*/
public function __construct(
public array $some16bitIntegers,
) {}
}

$reflector = TyphoonReflector::build(customTypeResolvers: [binary::int16]);

$propertyType = $reflector
->reflectClass(Message::class)
->properties()['some16bitIntegers']
->type();

var_dump(stringify($propertyType)); // "list<int<-32768, 32767>>"
```
Loading

0 comments on commit 6d6cbd0

Please sign in to comment.