vluzrmos/tinker
Tinker brings an interactive PHP REPL to Laravel via PsySH, adding the artisan tinker command so you can experiment with your app's code, test Eloquent queries, and inspect objects from the terminal without writing throwaway routes or scripts.
Verify compatibility before you type composer require. Last release was 2018-06-27, so its illuminate/* and psy/psysh constraints target Lumen 5.x. On a modern Lumen you will likely get an unresolvable dependency graph — check composer why-not vluzrmos/tinker and be prepared to fork, or jump straight to laravel/tinker (see Gotchas).
composer require vluzrmos/tinker
Register the provider manually. Lumen has no package discovery, so nothing works until you edit bootstrap/app.php. Register it after the Eloquent/Facade bootstraps, because the shell resolves models and facades the moment it starts:
// bootstrap/app.php
$app->withEloquent();
$app->withFacades();
$app->register(Vluzrmos\Tinker\TinkerServiceProvider::class);
Confirm the command exists before debugging anything else — a missing provider registration fails silently:
php artisan list | grep tinker
php artisan tinker
First use case: Lumen ships without make:model, factories, or seeders, so the REPL is your scaffolding tool. Open a shell and interrogate the schema you inherited:
Schema::getColumnListing('users');
App\Models\User::first();
App\Models\User::with('orders')->latest()->first();
Keep that first session read-only until you trust your environment.
Treat tinker as the missing make:/db: command set. Typical day-to-day loop in a Lumen service:
// explore
$u = App\Models\User::where('email', 'like', '%@acme.test')->first();
$u->orders()->count();
// mutate a single record instead of writing a throwaway route
$u->update(['plan' => 'pro']);
// build the query you'll paste into a repository
App\Models\Order::whereNull('paid_at')->where('created_at', '<', now()->subDays(30))->toSql();
Use --execute (or piped stdin) for repeatable smoke tests in CI, deploy scripts, and containers — this is where the package pays for itself most:
docker compose exec app php artisan tinker --execute="echo App\Models\User::count();"
# fallback if your version's command lacks --execute
echo 'echo App\Models\User::count();' | php artisan tinker
That gives you a post-deploy assertion — "the container can boot Lumen, connect to the DB, and resolve a model" — without adding a health-check route.
Probe jobs, events, and mail without HTTP. Since Lumen apps often lack HTTP surface for these, the shell is the fastest path to "does this dispatch, and does it serialize?"
dispatch(new App\Jobs\SyncAccount($account));
Event::dispatch(new App\Events\OrderPaid($order));
Mail::to('[email protected]')->queue(new App\Mail\Receipt($order));
Alias aggressively at the top of the session. Lumen's minimalism means long FQCNs everywhere:
use App\Models\{User, Order, Invoice};
$o = Order::find(42);
Wrap your own domain command around it if the team uses it constantly — subclass the command or shell out with --execute from a php artisan app:inspect command so there's one blessed entry point (and one place to add a production guard).
Guard registration to console so web requests don't pay for command bootstrapping:
if ($app->runningInConsole()) {
$app->register(Vluzrmos\Tinker\TinkerServiceProvider::class);
}
Point it at a scratch database. Set DB_DATABASE in a .env.tinker and run php artisan tinker --env=tinker so experiments never touch shared data.
psy/psysh v0.11+, or Lumen 6+. Your real options are: pin an old Lumen, vendor a fork with widened constraints, or register Laravel\Tinker\TinkerServiceProvider::class yourself — laravel/tinker works in Lumen today and is the recommended exit path. Budget a migration, not a patch.tinker in php artisan list almost always means you forgot $app->register(...) in bootstrap/app.php, not a broken install.withEloquent() / withFacades(). Otherwise User::first() throws "class not found" or the DB facade is unbound, and the error surfaces inside the REPL where it's easy to blame the shell.laravel/tinker and this package are installed, two classes claim the tinker signature; whichever the console kernel resolves first wins, and the other's options (--execute) vanish. Remove one.config/tinker.php is not auto-loaded in Lumen. If you need PsySH options, you must add $app->configure('tinker') and copy the config into your own config/; Lumen has no vendor:publish.ext-readline/pcntl give you a broken arrow-key prompt — and non-interactive piped input behaves subtly differently from --execute. Test your CI one-liner format locally in the same image.--execute support is version-dependent. Assume it may not exist on 2018-era code; stdin piping is the portable substitute.DB::transaction(function () { User::find(1)->delete(); throw new \Exception('rollback'); });
->get() on a large table OOMs the shell; use ->count(), ->take(5), or bump with php -d memory_limit=512M artisan tinker. APP_DEBUG and .env are whatever the CLI resolves — verify app()->environment() in the first line of every session.~/.config/psysh/config.php for personal shortcuts, require 'scratch.php'; inside the shell for reusable helpers, and Psy\Shell directly inside a custom command if you want a domain-scoped REPL (e.g., only Order operations) instead of a full application shell.How can I help you explore Laravel packages today?