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

Code Unit Reverse Lookup Laravel Package

sebastian/code-unit-reverse-lookup

Looks up which function or method a given line of code belongs to, a small utility from the PHPUnit ecosystem by Sebastian Bergmann. Install it via Composer as a project or dev dependency. Now a low maintenance project.

View on GitHub
Deep Wiki
Context7

Getting Started

sebastian/code-unit-reverse-lookup is a tiny, framework-agnostic PHP library that answers one question: given a file and a line number, which function or method does that line belong to? It is not a Laravel package — there is no service provider, facade, config file, or published assets. In a Laravel codebase you will mostly encounter it as a transitive dev dependency of phpunit/php-code-coverage.

First, check whether it is already present:

composer show sebastian/code-unit-reverse-lookup
composer why sebastian/code-unit-reverse-lookup

If it is only needed for local tooling or tests, install it as a dev dependency:

composer require --dev sebastian/code-unit-reverse-lookup

The first practical use case is mapping an uncovered or suspicious line to its owning method. The API is minimal:

use SebastianBergmann\CodeUnitReverseLookup\Wizard;

$wizard = new Wizard();

echo $wizard->lookUp(
    base_path('app/Http/Controllers/UserController.php'),
    42
);
// e.g. App\Http\Controllers\UserController::index

Look first at vendor/sebastian/code-unit-reverse-lookup/src/Wizard.php; the implementation is small enough to read end-to-end. There is no Laravel-specific documentation, so treat the source and its tests as the reference.

Implementation Patterns

1. Wrap it in a small application service. Since the class is final and framework-agnostic, keep it behind your own boundary so you can swap the implementation later:

namespace App\Support;

use SebastianBergmann\CodeUnitReverseLookup\Wizard;

final class CodeUnitLocator
{
    private Wizard $wizard;

    public function __construct()
    {
        $this->wizard = new Wizard();
    }

    public function forLine(string $file, int $line): string
    {
        $file = realpath($file) ?: $file;

        return $this->wizard->lookUp($file, $line);
    }
}

Register it as a singleton in AppServiceProvider when used repeatedly, because the wizard caches per-file parsing:

$this->app->singleton(\App\Support\CodeUnitLocator::class);

// Optional: only expose it in local/testing environments.
if ($this->app->environment(['local', 'testing'])) {
    $this->app->singleton(\App\Support\CodeUnitLocator::class);
}

2. Annotate custom coverage output. A common pattern is an Artisan command that reads a coverage report and enriches each line with its method name:

$wizard = new Wizard();

foreach ($uncoveredLines as $file => $lines) {
    foreach ($lines as $line) {
        $unit = $wizard->lookUp($file, $line);
        $this->line(sprintf('%s:%d — %s', $file, $line, $unit));
    }
}

This is useful for “which methods are least covered?” reports that are more actionable than raw line percentages.

3. Enrich local exception context. In a local-only error handler or debugging endpoint, map the exception’s getFile() and getLine() to a method name. Do not enable this in production unless you deliberately want that metadata exposed.

4. Custom PHPUnit extensions or test hooks. If you write a PHPUnit extension that reports uncovered code after a run, reverse lookup lets you group failing or uncovered lines by method rather than by raw line number. This is the package’s natural habitat: PHPUnit’s own coverage tooling uses it for exactly this purpose.

5. Static inspection commands. Any internal command that scans app/ and reports “where is this line?” — for example, a tool that flags very long methods by inspecting coverage or token data — can use the wizard as one small piece rather than building a parser.

Integration tips:

  • Always pass an absolute, existing path; use realpath() or base_path() to normalize.
  • Treat line numbers as 1-based, matching editors and stack traces.
  • Reuse one Wizard instance per process to benefit from its internal per-file cache.
  • Keep the dependency out of production runtime paths; it belongs in require-dev.

Gotchas and Tips

  • Low-maintenance project. The README explicitly marks it as low maintenance and carries an “unmaintained” badge. Pin it through your PHPUnit/php-code-coverage version rather than building critical product features on it.
  • Static, token-based lookup. It can only resolve code it can parse. Generated code, eval()-ed code, files with syntax errors, and dynamically declared functions may produce misleading or empty results.
  • Traits and anonymous classes are ambiguous. A line inside a trait will usually resolve to the trait method, not the consuming class; anonymous classes and closures can yield names that are not directly usable as class names. Do not assume the result is a fully qualified, instantiable class.
  • Do not parse the return string strictly. The format is a human-readable code-unit name (for example Class::method). Avoid regexing it apart; if you need reflection, resolve the class separately.
  • Path mismatches are the most common failure. Symlinks, Windows separators, relative paths, and coverage tools reporting a different path can all cause misses. Normalize both sides consistently.
  • Line boundaries are fuzzy. Attributes, docblocks, and the declaration line itself may map differently than you expect. Test with fixture files before relying on off-by-one-sensitive behavior.
  • Performance. Parsing is cached per file on the wizard instance, but creating a new Wizard for every line defeats that cache and can be slow on large files.
  • No extension points. The class is final and has no configuration. Compose around it rather than extending it.
  • No Laravel integration to configure. If you find yourself looking for a config key or facade, stop — there isn’t one. A small wrapper service and a singleton binding are all you need.
  • Debugging tip. Create a fixture file with known methods and assert on a substring of the result:
$result = (new Wizard())->lookUp(__DIR__ . '/fixtures/Sample.php', 12);

$this->assertStringContainsString('::sampleMethod', $result);
  • Fallback plan. If the package becomes incompatible with a future PHP or PHPUnit version, replace your wrapper internals with nikic/php-parser or the APIs exposed by php-code-coverage; keeping it behind CodeUnitLocator makes that swap cheap.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib