Weave Code
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 Laravel Package

sebastian/type

sebastian/type provides lightweight value objects for representing and working with PHP’s type system (built-in, class, union, intersection, nullable, etc.). Useful for static analysis tools, reflection helpers, and test utilities that need precise type modeling.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require sebastian/type --dev
    

    Add as a --dev dependency if only needed for testing/static analysis.

  2. First Use Case: Validate a type from a ReflectionType (e.g., from a method parameter or return type):

    use SebastianBergmann\Type\ReflectionMapper;
    use SebastianBergmann\Type\Type;
    
    $reflectionType = new \ReflectionNamedType(DateTimeImmutable::class);
    $type = ReflectionMapper::fromType($reflectionType);
    
    if ($type->isAssignableFrom(Type::fromString('DateTime'))) {
        // Type is assignable
    }
    
  3. Key Classes to Explore:

    • ReflectionMapper: Converts PHP reflection types to Type objects.
    • Type: Base class for all type representations (e.g., ObjectType, UnionType).
    • Type::fromString(): Parse type strings (e.g., "int|string").
  4. Where to Look First:


Implementation Patterns

Core Workflows

1. Type Introspection from Reflection

Use ReflectionMapper to extract types from PHP reflection objects (e.g., methods, properties):

$method = new \ReflectionMethod(MyClass::class, 'myMethod');
$returnType = ReflectionMapper::fromType($method->getReturnType());

if ($returnType->isObject()) {
    $objectType = $returnType->asObjectType();
    // Work with $objectType (e.g., validate against expected classes)
}

2. Type Validation in Laravel

Extend Laravel’s Validator or FormRequest with type-aware rules:

use SebastianBergmann\Type\Type;
use SebastianBergmann\Type\UnionType;

$validator = Validator::make($data, [
    'field' => ['required', function ($attribute, $value, $fail) {
        $expectedType = UnionType::fromTypes([
            Type::fromString('int'),
            Type::fromString('string'),
        ]);
        $actualType = Type::fromValue($value);
        if (!$expectedType->isAssignableFrom($actualType)) {
            $fail('The :attribute must be an int or string.');
        }
    }],
]);

3. Static Analysis Rules (PHPStan/Psalm)

Create custom rules using Type objects to enforce project-specific type constraints:

use SebastianBergmann\Type\Type;
use PHPStan\Rules\Rule;

class CustomTypeRule implements Rule
{
    public function getNodeType(): string
    {
        return \PHPStan\Node\MethodNode::class;
    }

    public function processNode(Node $node): array
    {
        $returnType = ReflectionMapper::fromType($node->getReturnType());
        if (!$returnType->isAssignableFrom(Type::fromString('App\Models\DTO'))) {
            return [sprintf(
                'Return type %s must be assignable from App\Models\DTO',
                $returnType->toString()
            )];
        }
        return [];
    }
}

4. DTO/Request Validation

Validate incoming data against strict type contracts:

use SebastianBergmann\Type\ObjectType;
use SebastianBergmann\Type\UnionType;

class UserRequest extends FormRequest
{
    public function rules()
    {
        return [
            'name' => ['required', 'string'],
            'age' => ['nullable', function ($attribute, $value, $fail) {
                $expectedType = UnionType::fromTypes([
                    Type::fromString('int'),
                    Type::fromString('null'),
                ]);
                $actualType = Type::fromValue($value);
                if (!$expectedType->isAssignableFrom($actualType)) {
                    $fail('The :attribute must be an int or null.');
                }
            }],
        ];
    }
}

5. API Contract Generation

Generate OpenAPI/Swagger schemas from Laravel controllers:

use SebastianBergmann\Type\ReflectionMapper;
use OpenApi\Generator;

$generator = new Generator();
$controller = new \ReflectionClass(MyController::class);

foreach ($controller->getMethods() as $method) {
    $returnType = ReflectionMapper::fromType($method->getReturnType());
    $generator->addResponse(
        $method->getName(),
        200,
        ['schema' => ['type' => $returnType->toString()]]
    );
}

Integration Tips

Laravel-Specific Patterns

  1. Service Container Binding Validation: Ensure DI bindings respect type hints:

    $container = app();
    $binding = $container->getBinding('MyService');
    $expectedType = Type::fromString('App\Services\MyServiceInterface');
    $actualType = Type::fromString($binding->getConcrete()[0]);
    
    if (!$expectedType->isAssignableFrom($actualType)) {
        throw new \RuntimeException('Invalid binding type for MyService');
    }
    
  2. Eloquent Model Attribute Types: Validate model attributes against expected types:

    use Illuminate\Database\Eloquent\Model;
    use SebastianBergmann\Type\Type;
    
    class User extends Model
    {
        protected static function booted()
        {
            static::saving(function (self $user) {
                foreach ($user->getAttributes() as $attribute => $value) {
                    $expectedType = Type::fromString($user->getTypeForAttribute($attribute));
                    $actualType = Type::fromValue($value);
                    if (!$expectedType->isAssignableFrom($actualType)) {
                        throw new \InvalidArgumentException(
                            "Attribute {$attribute} must be {$expectedType->toString()}"
                        );
                    }
                }
            });
        }
    }
    
  3. Custom Type Extensions: Extend Type for domain-specific types (e.g., Money, Email):

    use SebastianBergmann\Type\Type;
    
    class MoneyType extends Type
    {
        public static function fromString(string $type): self
        {
            return new self($type);
        }
    
        public function isAssignableFrom(Type $other): bool
        {
            return $other->toString() === 'Money' ||
                   $other->toString() === 'int';
        }
    }
    

Performance Optimization

  • Cache ReflectionMapper Instances:

    $mapper = new ReflectionMapper();
    // Reuse $mapper across multiple type checks
    
  • Lazy-Load Types: Defer type parsing until needed (e.g., in static analysis):

    $typeString = $method->getReturnType()->getName();
    $type = Type::fromString($typeString); // Parse only when required
    

Testing Patterns

  1. Assert Type Compatibility:

    use SebastianBergmann\Type\Type;
    
    public function testTypeAssignability()
    {
        $expected = Type::fromString('DateTimeInterface');
        $actual = Type::fromString('DateTimeImmutable');
    
        $this->assertTrue($expected->isAssignableFrom($actual));
    }
    
  2. Mock Type Checks:

    $mockType = $this->createMock(Type::class);
    $mockType->method('isAssignableFrom')->willReturn(true);
    
    $this->assertTrue($mockType->isAssignableFrom(Type::fromString('string')));
    

Gotchas and Tips

Pitfalls

  1. Class Alias Resolution:

    • Issue: Before v7.0.1, ReflectionMapper failed to resolve class aliases (e.g., DateTimeImmutable as DateTime).
    • Fix: Upgrade to ^7.0.1 and test with:
      $aliasType = Type::fromString('DateTimeImmutable');
      $baseType = Type::fromString('DateTime');
      $this->assertTrue($baseType->isAssignableFrom($aliasType));
      
  2. Union Types with iterable:

    • Issue: Older versions (<6.0.2) mishandled unions containing iterable (e.g., iterable|ArrayObject).
    • Fix: Ensure you’re on ^6.0.2 or later. Test with:
      $union = UnionType::fromTypes([
          Type::fromString('iterable'),
          Type::fromString('ArrayObject'),
      ]);
      $this->assertTrue($union->isAssignableFrom(Type::fromString('array')));
      
  3. **PHP Version

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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata