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

Better Types Laravel Package

spatie/better-types

Reflection-powered type checking for PHP: verify whether a ReflectionType or method signature accepts given arguments (including unions/nullables and named params). Useful for dispatching/overload-like method selection and safer dynamic calls.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/better-types
    

    No additional configuration is required—just autoload the package.

  2. First Use Case: Check if a value matches a type hint in a method or property:

    use Spatie\BetterTypes\BetterTypes;
    
    $value = 123;
    $reflectionMethod = new ReflectionMethod(SomeClass::class, 'someMethod');
    
    if (BetterTypes::accepts($reflectionMethod, $value)) {
        // Value matches the type hint
    }
    
  3. Key Classes:

    • BetterTypes – Main facade for type checks.
    • Type – Represents a type (e.g., Type::fromReflectionType($reflectionType)).
    • UnionType – Handles union types (e.g., Type::union([Type::string(), Type::int()])).

Where to Look First

  • README: Covers core functionality and examples.
  • Tests: Practical usage patterns.
  • API Docs: Generated docs for methods like accepts(), is(), etc.

Implementation Patterns

Core Workflows

  1. Type Validation in Controllers/Requests: Validate input against method type hints dynamically:

    public function store(Request $request) {
        $reflectionMethod = new ReflectionMethod($this, 'store');
        $input = $request->input('data');
    
        if (!BetterTypes::accepts($reflectionMethod, $input)) {
            throw new \InvalidArgumentException('Invalid input type');
        }
    }
    
  2. Union Type Handling: Check if a value matches any type in a union:

    $unionType = Type::union([Type::string(), Type::array()]);
    if ($unionType->accepts($value)) {
        // Valid for string or array
    }
    
  3. Named Types (PHP 8.2+): Validate custom types (e.g., DateTimeInterface):

    $type = Type::fromReflectionType(new ReflectionNamedType(DateTimeInterface::class));
    if ($type->accepts($value)) {
        // Valid DateTimeInterface
    }
    
  4. Property Validation: Check if a class property’s type hint matches a value:

    $property = new ReflectionProperty(SomeClass::class, 'propertyName');
    if (BetterTypes::accepts($property, $value)) {
        // Type-compatible
    }
    

Integration Tips

  • Laravel Request Validation: Combine with Laravel’s validation to enforce type hints:

    public function update(Request $request) {
        $reflectionMethod = new ReflectionMethod($this, 'update');
        $validated = $request->validate([
            'data' => ['required', fn($attr, $value) =>
                BetterTypes::accepts($reflectionMethod, $value) ?: 'Invalid type'
            ],
        ]);
    }
    
  • API Responses: Use to ensure response data matches expected types before serialization:

    $responseData = $this->service->process();
    $expectedType = Type::array()->of(Type::string());
    if (!$expectedType->accepts($responseData)) {
        throw new \RuntimeException('Response type mismatch');
    }
    
  • Testing: Assert type compatibility in PHPUnit:

    $this->assertTrue(BetterTypes::accepts($reflectionMethod, $validValue));
    $this->assertFalse(BetterTypes::accepts($reflectionMethod, $invalidValue));
    

Gotchas and Tips

Pitfalls

  1. Reflection Limitations:

    • Private/Protected Methods: Reflection may fail on non-public members. Use ReflectionMethod::newInstance() with null for private methods.
    • Dynamic Classes: If the class is generated at runtime (e.g., via eval), reflection may not work. Cache Reflection* objects if possible.
  2. Union Type Edge Cases:

    • Empty Unions: Type::union([]) will always reject values. Validate the union array isn’t empty.
    • Nullable Types: Use Type::nullable($type) explicitly for ?Type hints.
  3. PHP Version Quirks:

    • PHP 8.0-8.1: Named types (e.g., DateTimeInterface) may not resolve correctly. Use ReflectionNamedType explicitly.
    • PHP < 8.0: Some type features (e.g., array<int, string>) aren’t supported. Fall back to Type::array()->of(Type::int()).
  4. Performance:

    • Avoid repeated reflection calls in loops. Cache Reflection* objects or Type instances:
      private $cachedTypes = [];
      $type = $this->cachedTypes[$methodName] ??= Type::fromReflectionType($reflectionMethod->getType());
      

Debugging Tips

  1. Inspect Types: Use Type::describe() to debug complex types:

    $type = Type::fromReflectionType($reflectionMethod->getType());
    dump($type->describe()); // e.g., "array<int, string>"
    
  2. Common Errors:

    • "Type could not be resolved": Ensure the class/method exists and is autoloaded.
    • "Invalid type string": Check for typos in type names (e.g., DateTime vs. DateTimeInterface).
  3. Extension Points:

    • Custom Type Support: Extend Spatie\BetterTypes\Type to handle domain-specific types:
      class CustomType extends Type {
          public function accepts($value): bool {
              return $value instanceof CustomClass;
          }
      }
      
    • Override Default Behavior: Bind your custom type to the container:
      app()->bind(Type::class, fn() => new CustomType());
      

Configuration Quirks

  • No Config File: The package is zero-config. All behavior is runtime-driven.
  • Strict Mode: Enable PHP’s strict_types=1 for stricter type checks (recommended).

Pro Tips

  1. Combine with spatie/laravel-data: Use BetterTypes to validate Data objects before/after serialization:

    $data = new UserData($request->all());
    $type = Type::fromReflectionType(new ReflectionNamedType(UserData::class));
    if (!$type->accepts($data)) {
        throw new \InvalidArgumentException('Data type mismatch');
    }
    
  2. Type-Safe Collections: Validate collection items using Type::array()->of($itemType):

    $items = [1, 2, 3];
    $type = Type::array()->of(Type::int());
    if ($type->accepts($items)) {
        // All items are integers
    }
    
  3. Dynamic Type Generation: Generate types from strings for runtime validation:

    $type = Type::fromString('array<int, string>');
    if ($type->accepts($value)) {
        // Valid array<int, string>
    }
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4