Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Type Parser Laravel Package

vanio/type-parser

Vanio Type Parser is a lightweight PHP library that turns type declaration strings—unions, intersections, nullable types, generics, arrays and callables—into structured, inspectable objects, making it easy to analyze, validate and manipulate type information for reflection, tooling and code generati...

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and check its compatibility with your PHP version before wiring it into anything:

composer require vanio/type-parser

Where to look first

  1. README.md — it is the only reliable source of truth for the exact entry-point signature; the package is small and low-traffic, so the docs and the src/ directory are effectively the same specification.
  2. src/ — read the parser class and the value object it returns (usually a Type/TypeNode/array descriptor). This tells you what shapes you can expect: scalars, nullables, unions, arrays, and generics.
  3. composer.json — note the php-parser/nikic constraint. If you are on a recent PHP version, confirm the dependency tree resolves without forcing a downgrade.

First use case

The canonical use is reflection-free introspection of a DTO/model property when the native type is missing or too coarse:

use Vanio\TypeParser\TypeParser;

$parser = new TypeParser();

// Typical shape — verify the method name against the README:
$type = $parser->parsePropertyType(App\Dto\CreateOrder::class, 'items');
// e.g. resolves "@var array<int, App\Dto\OrderLine> $items"

A good first integration is a small serializer/hydrator or a form generator that needs to know "is this property a collection of OrderLine, and is it nullable?" before it walks the object graph. Start with one class, dump the parsed result, and confirm it matches what you expect before applying it across a codebase.

Implementation Patterns

Wrap it in a singleton service. Parsing docblocks is cheap but not free, and it is pure. Bind one instance in a service provider and inject it, rather than new TypeParser() at call sites:

$this->app->singleton(TypeParser::class, fn () => new TypeParser());

Cache per class+property. If you call the parser inside a loop (serializers, API resources, admin grids), memoize results keyed by Class::property. A simple array cache on the wrapper is enough for a request; use the Laravel cache with a tag or a file-based cache keyed by a hash of the class file's mtime if you need it across requests. Always invalidate when the source file changes in development.

Pair it with native reflection as a fallback. The most robust pattern is:

$reflection = new ReflectionProperty($class, $property);
$native = $reflection->getType();

if ($native !== null) {
    // use ReflectionNamedType / ReflectionUnionType
}

$parsed = $parser->parsePropertyType($class, $property); // docblock fallback

This keeps you honest on modern codebases where most properties already have native types, and reserves the parser for the genuinely dynamic cases (collections, generics, legacy code).

Use it in a custom cast or resource layer. A Castable-style attribute or an API resource that decides how to serialize a property can consult the parsed type to choose a transformer:

$type = $parser->parsePropertyType($this->model::class, $key);

if ($type->isCollection()) {
    return $value->map(fn ($item) => $this->transform($item, $type->itemType()));
}

Normalise the result into your own type object. Do not let the package's value objects leak throughout your domain. Map them into a small PropertyType VO with the handful of predicates you actually need (isNullable, isCollection, className, scalar). This makes swapping the parser out later a one-file change.

Gotchas and Tips

  • Docblock placement matters. The parser reads @var on the property. A @var on the class-level docblock, or one accidentally attached to a method, will not be found. Verify with ReflectionProperty::getDocComment().
  • Class-name resolution is the big unknown. Docblocks often say OrderLine relying on the file's use statements. Confirm whether the parser resolves imports to FQCNs or returns the raw string. If it returns raw strings, resolve them yourself against the file's namespace and imports (or require developers to write FQCNs — easier to enforce with a lint rule).
  • Nullable and union syntax is inconsistent. Expect ?Foo, Foo|null, and null|Foo to be handled, but test ?array<int, Foo> specifically; nested nullability is where small parsers break. Also check how mixed and missing @var are represented — usually as null or an empty type, not an exception.
  • Generics are shallow. array<int, Foo> and Foo[] are commonly supported, but Collection<Foo> or array{foo: string} (array shapes) likely are not. If you need shapes, do not assume support; add a fixture test for every type form you rely on.
  • Cache invalidation bites in dev. If you cache parsed types, a changed docblock with no changed native signature can leave you serving stale types. Key the cache on filemtime() of the class file during development, or simply disable cross-request caching outside production.
  • Dependency constraint risk. With very few dependents, the package is unlikely to track new nikic/php-parser majors quickly. Pin the package version in composer.json and watch for conflicts when you upgrade other tooling.
  • Debug by dumping the token stream or the raw docblock first. If a property returns an unexpected type, echo ReflectionProperty::getDocComment() before blaming the parser — nine times out of ten the annotation itself is malformed or mis-indented.
  • Extension points are limited. Do not expect a pluggable type-resolution strategy for imports or generics; if the parser does not support your case, add the preprocessing yourself (e.g., a normaliser that rewrites @var strings) rather than patching the package, which will be hard to maintain given its size.
  • Write your own fixture test suite. Given the low star count and dependent count, treat the package as an internal dependency: a handful of tests asserting behaviour for ?Foo, Foo|null, Foo[], array<int, Foo>, and a missing @var will protect you from being surprised by a patch release.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect