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

Bench Laravel Package

hoa/bench

hoa/bench is a lightweight PHP benchmarking library from the Hoa project. It helps measure execution time, compare code snippets, and profile performance with a simple API, making it easy to add repeatable benchmarks to PHP scripts and tests.

View on GitHub
Deep Wiki
Context7

Getting Started

hoa/bench is a standalone micro-benchmarking library, not a Laravel package. There is no service provider, no facade, no config file, and no auto-discovery. You get one class you instantiate yourself, and you read the timings back by casting it to a string.

Install it as a dev-only dependency:

composer require --dev hoa/bench

If Composer fights you, pin the last release explicitly (2017-01-11 / ^2.x) and remember it drags in the abandoned hoa/consistency, hoa/visitor, hoa/stream and hoa/protocol packages with it.

First use, in php artisan tinker — put a stopwatch around two competing implementations:

$bench = new Hoa\Bench\Bench();

$bench->start('strtotime');
for ($i = 0; $i < 100000; $i++) { strtotime('2024-01-01'); }
$bench->stop('strtotime');

$bench->start('carbon');
for ($i = 0; $i < 100000; $i++) { \Illuminate\Support\Carbon::parse('2024-01-01'); }
$bench->stop('carbon');

echo $bench;

Where to look first:

  1. vendor/hoa/bench/README.md — the nested-points example is the whole mental model.
  2. vendor/hoa/bench/Bench.php — start(), stop(), getPoint().
  3. vendor/hoa/bench/Point.php — the accessors (getTime(), aggregate stats) actually available to you. Trust this file over any blog post; the API surface is small and the docblocks are the spec.

Your first real use case should be a one-off: proving which of two Eloquent query shapes, two serializers, or two cache key strategies is faster, before you touch production code. That is where a 5-line tool beats firing up Telescope.

Implementation Patterns

Bind it, don't new it everywhere. If you use it in more than one place, register a non-singleton binding in a local-only provider:

// app/Providers/BenchServiceProvider.php
public function register(): void
{
    $this->app->bind(\Hoa\Bench\Bench::class, fn () => new \Hoa\Bench\Bench());
}

public function shouldBeRegistered(): bool
{
    return $this->app->isLocal();
}

Bind (not singleton) on purpose — see the Octane gotcha below.

Time named phases in a service. The library's real advantage over microtime() is that repeated start('db')/stop('db') calls with the same ID aggregate, and the point object exposes sum/min/max/average/variance. That makes "how long do my 47 queries in this request actually take, and what's the worst one" a one-liner instead of a manual array.

foreach ($queries as $q) {
    $bench->start('query');
    $result = $q->run();
    $bench->stop('query');
}

Nest points for phase breakdowns. Starting a point while another is open makes it a child, so a single echo gives you tree-shaped output (bootstrap → handler → render) rather than a flat list. Wrap in try/finally so an exception doesn't leave a point dangling.

Middleware for request-level totals:

public function handle($request, Closure $next)
{
    $bench = app(\Hoa\Bench\Bench::class);
    $bench->start('request');

    try {
        return $next($request);
    } finally {
        $bench->stop('request');
        Log::debug('request timing', ['report' => (string) $bench]);
    }
}

Log it, don't append it to the response — and guard the middleware registration with $this->app->isLocal().

Artisan command with a --bench flag is the cleanest integration point: php artisan report:generate --bench prints the report to the console instead of leaking timing into HTTP responses.

Migration pattern: wrap the two calls you actually use (start/stop + a report() string) behind your own tiny interface. When you swap to symfony/stopwatch later — and you probably will — it's a one-file change, since Stopwatch has essentially the same start($name) / stop($name) shape.

Gotchas and Tips

  • Archived since 2017, zero dependents. There will be no fixes. On PHP 8.2+ expect dynamic-property deprecation noise from the hoa/* stack; keep it out of production require and out of anything you ship to a client.
  • No reset method worth relying on. If you bind it as a singleton under Octane/RoadRunner, points accumulate across requests and your averages become fiction. Either bind fresh (as above) or instantiate per-request inside the middleware.
  • Always stop in LIFO order. Interleaved or mismatched start/stop across nested points produces confusing trees. Use try/finally per point.
  • Unknown IDs fail quietly-ish. getPoint('typo') won't give you a helpful error; you'll just see a missing row and wonder why. Grep your string literals — most "it's not measuring" bugs are a typo'd ID, not a library bug.
  • echo $bench is HTML-flavoured by default. Don't interpolate it straight into a JSON response or an Artisan info() line without checking the output first; capture the cast to string into a log channel instead.
  • Resolution is microtime-class, not hrtime. Fine for millisecond-scale work; don't draw conclusions from sub-microsecond deltas, and always run the loop long enough (100k iterations, not 10) that cold-start and opcache warm-up wash out.
  • No memory measurement. It times wall-clock only. If you're chasing allocation problems, this is the wrong tool — use memory_get_peak_usage().
  • Extension points are heavier than they look. The visitor-based rendering (hoa/visitor) means customising the report format is more ceremony than writing your own foreach over getPoint(). Just iterate the points and format it yourself.
  • Composer noise: composer audit will flag the transitive hoa/* packages. Since this is require-dev, the honest answer is "it's a local profiling tool, not shipped code" — but note it in your README so the next developer doesn't panic.
  • Consider not adopting it. Symfony Stopwatch is maintained, already in the dependency graph of most Laravel apps, and offers laps and categories. Laravel Telescope/Debugbar/Pulse cover the "what happened in this request" case better. hoa/bench earns a place only for quick, throwaway comparative benchmarks where its aggregate statistics are convenient — treat it as a scratchpad tool, not infrastructure.
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