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

Php Scoper Prefix Remover Laravel Package

pxlrbt/php-scoper-prefix-remover

Removes PHP-Scoper prefixes from prefixed class names and namespaces, helping you inspect or debug scoped code. Useful when you need unprefixed references back after running php-scoper.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm the premise before doing anything else. This is not a Laravel package and it has no service provider, facade, or config file you publish. It is a post-processing shim that only has meaning downstream of PHP-Scoper. If your composer.json doesn't have a scripts entry calling php-scoper add-prefix, and you don't ship a self-contained artifact (vendor-bundled PHAR, WordPress plugin/theme, white-label Laravel package that vendors vendor/), close the tab — adopting this adds a GPL-3.0 dependency to your lockfile for zero behaviour.

If you do ship scoped artifacts, the minimal path:

  1. Read src/ first. It's a one-class package. Ten minutes tells you the exact FQCN, the method signature, and whether the prefix is a constructor arg or hard-coded. Do this before writing any integration code — nothing in the package's README history is validated against current PHP 8.x.
  2. Read your own scoper.inc.php. You need the exact prefix literal your build produces. It's whatever you passed as --prefix / 'prefix' => to php-scoper add-prefix (Scoped\, AcmeScoped\, or a randomized value — see Gotchas).
  3. Install pinned, as a dev tool only:
composer require --dev pxlrbt/php-scoper-prefix-remover:1.0.0

Use an exact version, not a caret. There has been no release since 2021-11-30 and no SLA.

First use case: a support-triage Artisan command. This is the highest-value, lowest-risk entry point for a Laravel dev — it stays entirely inside your tooling, so the copyleft question never leaves your build environment:

// app/Console/Commands/HumanizeTrace.php
// Dev-only utility: paste a customer stack trace, get back readable class names.
$clean = (new PrefixRemover('Scoped\\'))->remove($this->argument('trace'));
$this->line($clean);

You pull a storage/logs/laravel.log excerpt or a customer-submitted trace off a scoped install, run it through this, and get Acme\Billing\Invoice instead of Scoped\Acme\Billing\Invoice. That's the whole day-to-day value for most teams.

Implementation Patterns

Pattern 1 — Build-time post-processing stage. The package's intended lane. Chain it immediately after php-scoper add-prefix and before archiving, in a standalone script (not an Artisan command — the build must not boot Laravel):

php-scoper add-prefix --prefix='Scoped\' --output-dir=build/
php build/strip-prefixes.php          # invokes the remover over generated stubs/templates

Only apply it to your own output surfaces — generated docblocks, exception message templates, hard-coded strings in your source — never to vendor/ or autoload maps. Rewriting a classmap breaks autoloading.

Pattern 2 — Golden-file regression test in CI. The silent-failure guard. Scoping and prefix-stripping are both literal string manipulation, so a broken prefix produces a no-op that ships happily. Assert on a fixture:

it('strips the scoped prefix from a sample trace', function () {
    $raw   = file_get_contents(base_path('tests/fixtures/scoped-trace.txt'));
    $clean = (new PrefixRemover('Scoped\\'))->remove($raw);

    expect($clean)->not->toContain('Scoped\\')
        ->toContain('Acme\\Billing\\Invoice');
});

Run this against the actual prefix your current build emits, read from the same source of truth as scoper.inc.php.

Pattern 3 — Output-boundary logging tap (runtime; legal review required first). If — and only if — legal clears GPL-3.0 for your distribution model, wire it at exactly one boundary rather than sprinkling str_replace calls. In a scoped Laravel app, that's a Monolog tap in config/logging.php:

'daily' => [
    'driver' => 'daily',
    'tap'   => [App\Logging\StripScopedPrefixes::class],
],

The tap class wraps the formatter and runs remove() over the formatted line. One boundary, one place to delete if the license position changes. Do not do this if the artifact is proprietary — a runtime component embeds GPL in the shipped work and propagates copyleft to the whole product.

Pattern 4 — Exception payload cleaning for API responses. Same licensing gate. In a scoped app's Handler::render, when app.debug is on, strip prefixes from $e->getMessage() and getTraceAsString() before they hit a customer-visible JSON error payload. Read the prefix from config rather than hard-coding, so the same value feeds scoper.inc.php:

// config/scoping.php — single source of truth, consumed by both scoper.inc.php and the app
'prefix' => env('SCOPER_PREFIX', 'Scoped\\'),

Integration tip — register it once. Bind it as a singleton in a service provider keyed off config('scoping.prefix') so you're not reconstructing the remover at every call site, and so the prefix literal exists in exactly one file.

Gotchas and Tips

GPL-3.0 is the gating risk, not the code. Build-time-only consumption confines exposure to your tooling. Runtime consumption — an exception handler, a Monolog processor, anything that ships inside the artifact — propagates strong copyleft to the entire distributed work. Decide which one you're doing before the spike, and never let the runtime variant in through the require-dev door. Also verify the package is excluded from the scoped vendor bundle so it doesn't ride along into the archive.

It strips strings, not identities. The package operates on text you hand it. It does not alias classes. Inside a scoped artifact, get_class($e), $e::class, instanceof, and reflection all still return the prefixed name — so any code that does class-name comparison or container resolution on a raw name still sees Scoped\.... Only the rendered output is fixed. If you expected transparent un-prefixing, you're looking at the wrong layer.

Never blind-replace inside serialized data. PHP's serialization format embeds byte lengths (s:31:"Scoped\Acme\Billing\Invoice"). A naive str_replace shortens the string without updating the length prefix and unserialize() fails at runtime in a customer's install — a bug that only surfaces in production. Strip before serializing, or leave serialized blobs alone entirely.

Escaping is where it silently breaks. 'Scoped\\' in PHP source, Scoped\ in shell, Scoped\\\\ in some config formats. An off-by-one backslash produces a no-op with no error. Conversely, a prefix that's too short or matched case-sensitively-inconsistently corrupts legitimate class names that merely start with the same characters. Anchor on the trailing separator (Scoped\), not the bare word (Scoped), and use preg_quote() if you extend it.

Randomized prefixes will bite you. php-scoper can generate a per-build random prefix. If yours does, you cannot hard-code the value — capture it as a build artifact (write it to a file during the build) and read it at both strip-time and at runtime.

The package likely won't read scoper.inc.php for you. Expect to pass the prefix explicitly, which means two configs that can drift. Collapse them into one shared config (see Pattern 3) or the drift is guaranteed the first time someone changes the prefix.

Abandonment posture. 10 stars, zero dependents, no release since 2021-11-30, single maintainer, no security disclosure process. Zero dependents means nobody else has validated it against PHP 8.2/8.3 or current PHP-Scoper, so assume breakage until a test proves otherwise. Pin exact, fork internally, add your own tests — or, realistically, spend the hour writing the ~30-line equivalent yourself and skip the license question, the bus factor, and the coupling to PHP-Scoper's non-public output conventions.

Extension points are effectively nil. No allow/deny lists, no regex rules, no nested-array or $_SERVER trace walking. If you need case-insensitive matching, structured-trace traversal, or multiple prefixes, you're writing the wrapper anyway — at which point the in-house helper is the cheaper answer.

Debugging a no-op: dump the raw, unstripped string alongside the configured prefix and compare bytes (bin2hex(), or str_contains() on the literal). Nine times out of ten the prefix in the shipped build differs from the one in your local scoper.inc.php, and the library is behaving correctly.

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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator