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

Backtrace Laravel Package

spatie/backtrace

Spatie Backtrace makes PHP backtraces easier than debug_backtrace(): frames are aligned correctly and exposed as Frame objects with file, line, class, method, and optional arguments. Simple API to capture, inspect, and work with stack traces.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

Install via Composer:

composer require spatie/backtrace

First Use Case: Debugging a Method Call

use Spatie\Backtrace\Backtrace;

// Get the current backtrace with application context
$backtrace = Backtrace::create()
    ->applicationPath(base_path())
    ->trimFilePaths();

$frames = $backtrace->frames();

// Inspect the first application frame
$firstAppFrame = $frames[0];
dump($firstAppFrame->method); // e.g., "handlePayment"
dump($firstAppFrame->file);   // e.g., "app/Services/PaymentService.php"

Key Initial Actions

  1. Set Application Context (Critical for filtering vendor vs. app frames):
    Backtrace::create()->applicationPath(base_path())
    
  2. Trim File Paths (For cleaner output):
    ->trimFilePaths()
    
  3. Inspect Frames (Start with frames() to explore structure).

Implementation Patterns

1. Debugging Workflows

Exception Handling

try {
    // Risky operation
} catch (Throwable $e) {
    $backtrace = Backtrace::createForThrowable($e)
        ->applicationPath(base_path())
        ->withArguments()
        ->reduceArguments();

    $frames = $backtrace->frames();
    // Log or display frames for debugging
}

Middleware/Service Debugging

public function handle($request, Closure $next) {
    $backtrace = Backtrace::create()
        ->startingFromFrame(fn ($frame) => $frame->class === Middleware::class)
        ->limit(5);

    // Log or inspect $backtrace->frames() for middleware flow
    return $next($request);
}

2. Advanced Frame Inspection

Filtering Frames

// Skip vendor frames and limit to 3 app frames
$frames = Backtrace::create()
    ->applicationPath(base_path())
    ->startingFromFrame(fn ($frame) => $frame->applicationFrame)
    ->limit(3)
    ->frames();

Code Snippet Extraction

$frame = $frames[0];
$snippet = $frame->getSnippetAsString(); // Returns code snippet around lineNumber

3. Custom Argument Reduction

For Domain-Specific Types

use Spatie\Backtrace\Arguments\ArgumentReducer;
use Spatie\Backtrace\Arguments\ReducedArgument;
use Spatie\Backtrace\Arguments\UnReducedArgument;

class UserIdReducer implements ArgumentReducer {
    public function execute($argument): ReducedArgumentContract {
        if ($argument instanceof UserId) {
            return new ReducedArgument(
                "User ID: {$argument->value()}",
                UserId::class
            );
        }
        return UnReducedArgument::create();
    }
}

// Usage
$backtrace = Backtrace::create()
    ->withArguments()
    ->reduceArguments([
        new UserIdReducer(),
        // ... other reducers
    ]);

4. Integration with Laravel

Logging Exceptions

use Illuminate\Log\Logger;
use Spatie\Backtrace\Backtrace;

app(Logger::class)->error('Payment failed', [
    'backtrace' => Backtrace::createForThrowable($e)
        ->applicationPath(base_path())
        ->withArguments()
        ->reduceArguments()
        ->getAsString(),
]);

Custom Error Pages

// In App\Exceptions\Handler
public function render($request, Throwable $exception) {
    $backtrace = Backtrace::createForThrowable($exception)
        ->applicationPath(base_path())
        ->trimFilePaths()
        ->limit(10);

    return response()->view('errors.custom', [
        'backtrace' => $backtrace->getAsString(),
    ]);
}

Gotchas and Tips

Pitfalls

  1. zend.exception_ignore_args INI Setting

    • If enabled (1), createForThrowable() won’t include arguments.
    • Fix: Disable it in php.ini or .user.ini before throwing exceptions:
      zend.exception_ignore_args=0
      
  2. File Path Edge Cases

    • Frames with directory paths (e.g., /app/) will crash without trimFilePaths().
    • Solution: Always use trimFilePaths() with applicationPath():
      Backtrace::create()->applicationPath(base_path())->trimFilePaths();
      
  3. Vendor Frame Misclassification

    • Laravel’s artisan and Statamic’s please are always marked as vendor frames (even in root).
    • Workaround: Manually filter them out:
      ->startingFromFrame(fn ($frame) =>
          $frame->applicationFrame &&
          !str_contains($frame->file, ['artisan', 'please'])
      )
      
  4. Performance with withArguments()

    • Collecting arguments is slow for deep backtraces.
    • Tip: Use sparingly and cache results if reused:
      $cachedBacktrace = Backtrace::create()
          ->withArguments()
          ->remember(); // Hypothetical; implement caching manually
      

Debugging Tips

  1. Inspect Frame Properties Dump a frame to see all available data:

    dd($frame->toArray()); // Includes: file, lineNumber, class, method, etc.
    
  2. Check applicationFrame Logic

    • Use firstApplicationFrameIndex() to find the first app frame:
      $index = $backtrace->firstApplicationFrameIndex();
      $appFrames = array_slice($frames, $index);
      
  3. Handle Non-Existent Files

    • If open_basedir restricts file access, use a custom CodeSnippetProvider:
      $backtrace->setCodeSnippetProvider(new CustomSnippetProvider());
      

Extension Points

  1. Custom Argument Reducers

    • Extend ArgumentReducer for domain-specific types (e.g., UUIDs, custom DTOs).
  2. Code Snippet Providers

    • Implement CodeSnippetProvider to fetch code from external sources (e.g., GitHub).
  3. Frame Filtering

    • Override startingFromFrame() logic for project-specific needs:
      ->startingFromFrame(fn ($frame) =>
          str_contains($frame->file, ['app/Http/Controllers'])
      )
      

Configuration Quirks

  1. applicationPath() Must Precede trimFilePaths()

    • Order matters! trimFilePaths() relies on applicationPath() for path normalization.
  2. withObject() Limitations

    • Objects are never included in throwable backtraces (PHP limitation).
    • Workaround: Use withObject() for non-throwable backtraces.
  3. PHP 8.4+ Compatibility

    • Uses modern PHP features (e.g., readonly properties). Test on target PHP version.

Pro Tips

  • Log Backtraces for Critical Paths:
    Backtrace::create()
        ->applicationPath(base_path())
        ->withArguments()
        ->reduceArguments()
        ->getAsString(); // Log this for auditing
    
  • Use in Tests:
    $this->assertEquals(
        'App\\Services\\PaymentService',
        Backtrace::create()->frames()[0]->class
    );
    
  • Combine with whoops: Integrate for enhanced error pages:
    $whoops->addSingleFrameHandler(function (Whoops\Frame $frame) {
        $backtrace = Backtrace::createForThrowable($frame->getThrowable())
            ->applicationPath(base_path())
            ->trimFilePaths();
        return $backtrace->getAsString();
    });
    
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
milesj/emojibase
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