symfony/stopwatch
Symfony Stopwatch is a lightweight profiling utility to measure execution time and memory usage in PHP. Start/stop named events, record laps, and group timings into sections (phases) to benchmark code paths and understand performance bottlenecks.
Install via Composer:
composer require symfony/stopwatch
use Symfony\Component\Stopwatch\Stopwatch;
public function index(Stopwatch $stopwatch)
{
$stopwatch->start('controller_execution');
// Your controller logic here
$data = $this->someService->fetchData();
$event = $stopwatch->stop('controller_execution');
// Log or display results
\Log::info("Controller took {$event->getDuration()}ms");
return view('home', compact('data'));
}
public function handle($request, Closure $next)
{
$stopwatch = app(Stopwatch::class);
$stopwatch->start('middleware_execution');
$response = $next($request);
$event = $stopwatch->stop('middleware_execution');
\Log::debug("Middleware took {$event->getDuration()}ms");
return $response;
}
public function fetchData(Stopwatch $stopwatch)
{
$stopwatch->start('service_fetch_data');
// Business logic
$result = $this->repository->findAll();
$event = $stopwatch->stop('service_fetch_data');
\Log::debug("Service method took {$event->getDuration()}ms");
return $result;
}
public function getUser($id)
{
$stopwatch = app(Stopwatch::class);
$stopwatch->start('user_query');
$user = User::find($id);
$event = $stopwatch->stop('user_query');
\Log::debug("User query took {$event->getDuration()}ms");
return $user;
}
public function complexOperation(Stopwatch $stopwatch)
{
$stopwatch->openSection('data_processing');
$stopwatch->start('validation');
// Validation logic
$stopwatch->stop('validation');
$stopwatch->start('transformation');
// Transformation logic
$stopwatch->stop('transformation');
$stopwatch->stopSection('data_processing');
}
public function register()
{
$this->app->singleton(Stopwatch::class, function () {
return new Stopwatch();
});
}
$stopwatch = app(Stopwatch::class);
$stopwatch->start('event_name');
// ... code ...
$event = $stopwatch->stop('event_name');
\Log::channel('performance')->info([
'event' => 'event_name',
'duration' => $event->getDuration(),
'memory' => $event->getMemory(),
'timestamp' => now()->toIso8601String()
]);
protected function handle()
{
$stopwatch = app(Stopwatch::class);
$stopwatch->start('command_execution');
// Command logic
$this->processData();
$event = $stopwatch->stop('command_execution');
$this->info("Command executed in {$event->getDuration()}ms");
}
Forgetting to Stop Events
try {
$stopwatch->start('event');
// Code
} finally {
$stopwatch->stop('event');
}
Memory Usage Overhead
$stopwatch = new Stopwatch(false); // Disable memory tracking
Nested Events with Same Name
Laravel Dependency Injection
Check All Events
foreach ($stopwatch->getEvents() as $event) {
\Log::debug("{$event->getName()}: {$event->getDuration()}ms");
}
Inspect Sections
foreach ($stopwatch->getSections() as $section) {
\Log::debug("Section {$section->getName()} took {$section->getDuration()}ms");
}
Lap Timing
lap() to measure intermediate steps within an event:
$stopwatch->start('event');
$stopwatch->lap('step_1');
// Code for step 1
$stopwatch->lap('step_2');
// Code for step 2
$event = $stopwatch->stop('event');
Custom Event Data
$event = $stopwatch->stop('event');
$event->setData(['query' => 'SELECT * FROM users']);
Event Listeners
$stopwatch->addListener(function (StopwatchEvent $event) {
if ($event->getDuration() > 1000) { // 1 second
\Log::warning("Slow event: {$event->getName()}");
}
});
Stopwatch Storage
$event = $stopwatch->stop('event');
PerformanceLog::create([
'event_name' => $event->getName(),
'duration_ms' => $event->getDuration(),
'memory_bytes' => $event->getMemory(),
'created_at' => now()
]);
Minimize Overhead
if (app()->environment('local')) {
$stopwatch->start('event');
// Code
$stopwatch->stop('event');
}
Batch Logging
$events = [];
$stopwatch->addListener(function (StopwatchEvent $event) use (&$events) {
$events[] = $event;
});
// Later, log all events at once
PerformanceLog::insert(array_map(function ($event) {
return [
'event_name' => $event->getName(),
'duration_ms' => $event->getDuration(),
'created_at' => now()
];
}, $events));
Avoid Blocking
$stopwatch->addListener(function (StopwatchEvent $event) {
dispatch(new LogPerformanceEvent($event))->onQueue('performance');
});
How can I help you explore Laravel packages today?