vollbehr/php-reader
php-reader is a small PHP package that provides reader utilities for working with input data in a clean, consistent way. It aims to simplify common reading tasks in PHP applications and installs easily via Composer.
The bridge package is the entry point for Laravel, not the core library. Requiring vollbehr/<core> alone gives you the classes but no service provider, no config, and no container bindings.
composer require vollbehr/laravel-<core>:"^2.0@RC"
php artisan vendor:publish --tag=vollbehr-config
Steps, in order:
php -v must report 8.2 or higher. Laravel 10 projects on PHP 8.1 will fail Composer resolution outright — this is the single most common blocker on upgrade.config/app.php. Run php artisan about and look for the package in the discovered list, or php artisan package:discover and read the output.config/vollbehr.php before writing any code. The bridge's config helper is where the library's options are exposed; almost every "how do I configure X" question is answered there rather than in the library's own docs.final class NormaliseController
{
public function __construct(private \Vollbehr\...\Service $service) {}
public function __invoke(Request $request): JsonResponse
{
return response()->json(['result' => $this->service->handle($request->input('value'))]);
}
}
Resist the old PEAR/Google Code habit of new-ing the class or calling static methods directly. The bridge exists so you don't have to.
Depend on the container binding, not the concrete class. The bridge binds the library's primary service; type-hint that interface (or the manager class) in constructors and let Laravel resolve it. This is what makes the library swappable in tests.
Keep the vendor namespace in one place. Wrap the library in a thin application-level adapter — one class, one file that imports Vollbehr\.... When 2.0.0 final lands and then 3.0 after it, you change one file instead of forty. This is also where you normalise exceptions into your app's own exception types.
Use the new PHP 8.2 features deliberately. The release adds enums and readonly members. In your own code:
match on the library's enums instead of comparing ints or strings — you get exhaustiveness checking for free.clone-and-modify a readonly object; rebuild it through the bridge's config factory.For queue jobs and events, pass scalars or the library's readonly DTOs — never the service itself. Readonly value objects serialise cleanly; the manager/service generally does not.
Multiple configurations (per-tenant, per-locale, per-connection): the container binding is typically a singleton built from config/vollbehr.php. If you need a second, differently-configured instance, instantiate the core class directly with explicit arguments inside a small factory of your own rather than fighting the singleton.
Testing: bind a fake or stub in setUp() via $this->app->instance(...), or use the facade's shouldReceive if the bridge ships one. The library's own behaviour is not worth re-testing; assert your adapter's contract.
Console commands and migrations: resolve lazily with app(...) at handle time. Resolving a service that reads config inside register() will bite you under config:cache.
The namespace change is the breaking change that will actually hurt. Everything moved under Vollbehr\ with PSR-4. Audit for:
'Net_...', 'Vollbehr_...' style references).class_exists(), is_a(), and instanceof checks against old names.autoload.classmap entries or files includes.A temporary class_alias() block in a service provider is a legitimate short-term bridge if you can't rip everything out at once, but it defeats the point of the migration; schedule its removal.
Serialized payloads from before 2.0 will fail. Cached objects, queued job payloads, and anything in cache or failed_jobs referencing old class names unserialize to __PHP_Incomplete_Class — often without an obvious error, just a silently broken object. Before deploying: flush the cache (php artisan cache:clear, and tagged caches explicitly), and drain or migrate the queue rather than letting old jobs run against new code.
RC stability flag. ^2.0@RC requires the constraint to be explicit; without @RC Composer won't install it against a default minimum-stability. Pin tightly and don't let the RC float into a production composer.lock without an intentional decision — API churn between rc1 and 2.0.0 final is expected.
Keep the bridge and core in lockstep. The Laravel bridge constrains the core version. Upgrading one without the other produces either a Composer conflict or, worse, a bridge binding a class that no longer exists. Bump them in the same commit.
After upgrading, always php artisan config:clear (or config:cache). A cached config/vollbehr.php from the previous version is missing new keys and will produce confusing null behaviour that looks like a library bug. Re-publish the config and diff it against your committed copy — don't blindly overwrite, since you'll lose local customisations.
Debugging the binding: get_class(app(\Vollbehr\...\Service::class)) tells you what the container actually resolved. If it throws, the provider didn't register — check discovery and that you required the bridge, not just the core.
Extension point: the bridge binds its service in register(). To substitute your own implementation, rebind in a provider registered after the bridge (later in bootstrap/providers.php) or in a resolving() callback. Rebinding earlier is silently overwritten.
Carried-over workarounds are now dead weight. This release fixes the historical Google Code bug list. If your codebase has patches, monkey-patches, or comments citing old ticket numbers, grep for them and delete — leftover workarounds around fixed bugs usually cause more damage than the original bug.
PHP 8.2 features are load-bearing, not cosmetic. Typed properties and readonly members mean passing null where a value is expected now throws TypeError at the boundary rather than failing later with a confusing message. If you were relying on loose coercion from the old code, expect loud failures — and treat them as correctness fixes rather than regressions to be worked around.
How can I help you explore Laravel packages today?