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

Stringifier Laravel Package

respect/stringifier

Respect\Stringifier converts any PHP value into a readable string for logging, debugging, and error messages. Use the stringify() function or the HandlerStringifier object. Secure-by-default handling of strings in newer versions. Requires PHP 8.3+.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer:

composer require respect/stringifier

First Use Case: Replace ad-hoc string casting in Laravel logs or debugging:

use function Respect\Stringifier\stringify;

// Before: (string)$request->input('data')
// After:
Log::debug('Request data:', stringify($request->input('data')));

// For objects/arrays:
Log::debug('User:', stringify($user));

Key Starting Points:

  1. Function API: Use stringify($value) for quick conversions.
  2. Object API: Use HandlerStringifier for customization (e.g., HandlerStringifier::create()).
  3. Laravel Integration: Override toString() in models or use a macro for Eloquent collections:
    use Respect\Stringifier\stringify;
    
    Collection::macro('toString', function () {
        return stringify($this->all());
    });
    

Implementation Patterns

Core Workflows

  1. Logging and Debugging:

    // Monolog handler
    $handler = new \Monolog\Handler\StreamHandler(storage_path('logs/debug.log'));
    $handler->pushProcessor(function ($record) {
        $record['context']['data'] = stringify($record['context']['data'] ?? null);
        return $record;
    });
    
    // Artisan commands
    $this->info('Processing: ' . stringify($this->argument('data')));
    
  2. API Responses:

    // Custom JSON response formatter
    Response::macro('stringify', function ($data) {
        return response()->json(['data' => stringify($data)]);
    });
    
    // Usage:
    return response()->stringify($complexObject);
    
  3. Validation Error Messages:

    // FormRequest validation
    public function failedValidation(Validator $validator) {
        $errors = stringify($validator->errors()->toArray());
        return response()->json(['errors' => $errors], 422);
    }
    
  4. Caching Keys:

    // Dynamic cache keys for complex objects
    $cacheKey = 'user_' . stringify($user->id . $user->role);
    Cache::put($cacheKey, $user);
    

Laravel-Specific Patterns

  1. Eloquent Model Stringification:

    // Override toString() in a model
    public function toString(): string {
        return stringify([
            'id' => $this->id,
            'name' => $this->name,
            'created_at' => $this->created_at,
        ]);
    }
    
  2. Service Container Binding:

    // Bind a custom stringifier for specific use cases
    $app->bind('custom.stringifier', function () {
        $handler = HandlerStringifier::create();
        $handler->addStringifier(new class implements Handler {
            public function handle(mixed $raw, int $depth): ?string {
                if ($raw instanceof YourCustomClass) {
                    return 'CustomClass{' . $raw->id . '}';
                }
                return null;
            }
        });
        return $handler;
    });
    
  3. Exception Handling:

    // Custom exception formatter
    App::error(function (Throwable $e, $request) {
        return response()->json([
            'error' => stringify($e),
            'trace' => stringify($e->getTrace()),
        ]);
    });
    
  4. Testing:

    // Assert stringified output in tests
    $this->assertEquals(
        'User{id:1,name:"John"}',
        stringify(new User(['id' => 1, 'name' => 'John']))
    );
    

Gotchas and Tips

Pitfalls

  1. Version 2.0 Security Risks:

    • Problem: Exposes internal class/interface names in stringified output.
    • Fix: Downgrade to v1.x or disable sensitive detection:
      $stringifier = HandlerStringifier::create();
      $stringifier->setOptions(['detect_classes' => false]);
      
  2. Performance with Deep Objects:

    • Problem: Recursive stringification of deeply nested objects may hit PHP’s recursion limit.
    • Fix: Set a depth limit:
      $stringifier = HandlerStringifier::create();
      $stringifier->setMaxDepth(5); // Default is 10
      
  3. Resource Leaks:

    • Problem: Stringifying resources (e.g., tmpfile()) may not close them properly.
    • Fix: Avoid stringifying resources directly; use get_resource_type() or custom handlers.
  4. Closure/Callable Output:

    • Problem: Closures may expose sensitive function names.
    • Fix: Mask or disable callable detection:
      $handler = CompositeHandler::create();
      $handler->removeStringifier(CallableStringifier::class);
      
  5. False Positives in is_callable:

    • Problem: Arrays like ['foo', 'bar'] may be misinterpreted as callables.
    • Fix: Use v1.x or whitelist safe arrays.

Debugging Tips

  1. Inspect Handlers:

    • List registered handlers to debug why a value isn’t stringified as expected:
      $stringifier = HandlerStringifier::create();
      print_r($stringifier->getHandlers());
      
  2. Custom Fallback:

    • Replace DumpStringifier with a custom fallback for unsupported types:
      $stringifier = new HandlerStringifier(
          CompositeHandler::create(),
          new class implements Stringify {
              public function stringify(mixed $raw, int $depth): string {
                  return '[Unsupported: ' . gettype($raw) . ']';
              }
          }
      );
      
  3. Logging Stringifier Output:

    • Log the stringification process to debug edge cases:
      $stringifier = HandlerStringifier::create();
      $stringifier->addStringifier(new class implements Handler {
          public function handle(mixed $raw, int $depth): ?string {
              Log::debug('Stringifying:', ['value' => $raw, 'depth' => $depth]);
              return null; // Let other handlers process it
          }
      });
      

Extension Points

  1. Custom Handlers:

    • Create a handler for domain-specific types (e.g., Carbon\Carbon):
      $handler = new class implements Handler {
          public function handle(mixed $raw, int $depth): ?string {
              if ($raw instanceof Carbon\Carbon) {
                  return $raw->format('Y-m-d H:i:s');
              }
              return null;
          }
      };
      $stringifier->addStringifier($handler);
      
  2. Pre/Post Processing:

    • Wrap the stringifier to add metadata or sanitize output:
      $stringifier = new class($delegate) implements Stringify {
          public function __construct(private Stringify $delegate) {}
          public function stringify(mixed $raw, int $depth): string {
              $result = $this->delegate->stringify($raw, $depth);
              return '[Sanitized] ' . str_replace(['{', '}'], '', $result);
          }
      };
      
  3. Conditional Stringification:

    • Skip stringification for specific types (e.g., sensitive data):
      $handler = new class implements Handler {
          public function handle(mixed $raw, int $depth): ?string {
              if ($raw instanceof SensitiveData) {
                  return '[REDACTED]';
              }
              return null;
          }
      };
      

Laravel-Specific Quirks

  1. Eloquent Relationships:

    • Stringifying Eloquent models with lazy-loaded relationships may cause N+1 queries.
    • Fix: Eager-load relationships first:
      $user = User::with('posts')->find(1);
      stringify($user); // Safe
      
  2. Collection Macros:

    • If using Collection::macro('toString'), ensure it doesn’t conflict with existing macros:
      if (!Collection::hasMacro('toString')) {
          Collection::macro('toString', function () {
              return stringify($this->all());
          });
      }
      
  3. Service Provider Boot:

    • Register a global stringifier instance if needed:
      public function boot() {
          $app->singleton('stringifier', function () {
              return HandlerStringifier::create();
          });
      }
      
  4. Testing:

    • Mock the stringifier in tests to avoid real object instantiation:
      $this->app->instance('stringifier', Mockery::mock(Stringify::class));
      
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.
labyrinthe/connect-php
encore2/laravel-admin2
cboxdk/laravel-console-kit
shapecode/doctrine-dbal-datetimeutc
gilads-otiannoh254/inertia-protocol
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
adachsoft/cli-process-tester
adachsoft/changelog-linter
adachsoft/collection
adachsoft/php-code-style
adachsoft/api-version-bundle