blackfire/php-sdk
Blackfire PHP SDK provides a client for programmatic profiling with Blackfire, plus integrations like PHPUnit. Includes an optional proxy to inspect profiling traffic and a pure-PHP probe fallback for environments where the Blackfire extension can’t be installed.
Installation:
composer require blackfire/php-sdk
Ensure your Laravel app has the Blackfire PHP extension installed (or use the PHP Probe fallback).
Environment Configuration:
Add Blackfire credentials to .env:
BLACKFIRE_CLIENT_ID=your_client_id
BLACKFIRE_CLIENT_TOKEN=your_client_token
BLACKFIRE_SERVER_ID=your_server_id
BLACKFIRE_SERVER_TOKEN=your_server_token
First Profile: In a Laravel route or controller:
use Blackfire\Client;
route('profile', function () {
$client = new Client();
$client->startScenario('My Laravel App');
// Your code to profile
User::with('posts')->find(1);
$client->closeScenario();
});
View Results: Profiles will appear in your Blackfire.io dashboard.
use Blackfire\Client;
class UserController extends Controller
{
public function show(User $user)
{
$client = app(Client::class);
$client->startScenario('User Show');
// Profile this entire method
$posts = $user->posts()->with('comments')->get();
$client->closeScenario();
return view('user.show', compact('user', 'posts'));
}
}
Profile all requests via middleware:
use Blackfire\Client;
class BlackfireMiddleware extends Middleware
{
public function handle(Request $request, Closure $next)
{
$client = app(Client::class);
$client->startScenario('HTTP Request: ' . $request->path());
$response = $next($request);
$client->closeScenario();
return $response;
}
}
Register in app/Http/Kernel.php:
protected $middleware = [
\App\Http\Middleware\BlackfireMiddleware::class,
];
Profile CLI commands:
use Blackfire\Client;
use Illuminate\Console\Command;
class OptimizeCommand extends Command
{
protected $signature = 'app:optimize';
protected $description = 'Optimize the application';
public function handle()
{
$client = app(Client::class);
$client->startScenario('Artisan Optimize');
// Your optimization logic
Artisan::call('cache:clear');
Artisan::call('config:clear');
$client->closeScenario();
}
}
Profile queue workers:
use Blackfire\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
class ProcessPodcast implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public function handle()
{
$client = app(Client::class);
$client->startScenario('ProcessPodcast Job');
// Your job logic
$podcast = Podcast::find($this->podcastId);
$podcast->process();
$client->closeScenario();
}
}
For Laravel apps using Symfony components:
use Blackfire\Client;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class BlackfireSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => 'onKernelRequest',
];
}
public function onKernelRequest(RequestEvent $event)
{
$client = app(Client::class);
$client->startScenario('Symfony Request: ' . $event->getRequest()->getPathInfo());
// Event handling...
}
}
Profile HTTP requests with Laravel's HTTP client:
use Blackfire\Client;
use Illuminate\Support\Facades\Http;
$client = app(Client::class);
$client->startScenario('External API Call');
$response = Http::withOptions([
'blackfire' => [
'title' => 'GitHub API',
'url' => 'https://api.github.com',
]
])->get('https://api.github.com/user');
$client->closeScenario();
Focus on specific queries:
use Blackfire\Client;
use Illuminate\Support\Facades\DB;
$client = app(Client::class);
$client->startScenario('Database Query');
$results = DB::connection('mysql')->select('SELECT * FROM users WHERE active = ?', [1]);
$client->closeScenario();
BLACKFIRE_CLIENT_ID and BLACKFIRE_CLIENT_TOKEN are set. Without them, profiling will fail silently.BLACKFIRE_SERVER_ID and BLACKFIRE_SERVER_TOKEN are required.BLACKFIRE_BUILD_UUID to group profiles logically:
BLACKFIRE_BUILD_UUID=git-commit-hash
closeScenario() can lead to orphaned profiles or memory leaks. Use a finally block or Laravel's illuminate/support helpers:
$client->startScenario('My Scenario');
try {
// Code to profile
} finally {
$client->closeScenario();
}
$client->startScenario('User Profile', ['tags' => ['auth']]);
xhprof is installed and configured. The probe adds ~5-10% overhead.ProfileNotReadyException, ensure:
php -m | grep blackfire).blackfire.io.$client->getProfile($profileId, ['maxRetries' => 5]);
$client = new Client(['logger' => new \Monolog\Logger('blackfire', [new \Monolog\Handler\StreamHandler('php://stderr', \Monolog\Logger::DEBUG)])]);
if (str_starts_with(request()->path(), '/health')) {
return response()->json(['status' => 'ok']);
}
$client->startScenario('API Request', ['tags' => ['api', 'v1']]);
telescope).$client->addMetric('users_count', User::count());
$client->addMetric('cache_hits', Cache::stats()['hits'] ?? 0);
$config = config('blackfire.'.app()->environment());
$client = new Client($config);
Define in config/blackfire.php:
return [
'local' => [
'clientId' => env('BLACKFIRE_CLIENT_ID_LOCAL'),
'clientToken' => env('BLACKFIRE_CLIENT_TOKEN_LOCAL'),
],
'production' => [
'clientId' => env('BLACKFIRE_CLIENT_ID'),
'clientToken' => env('BLACKFIRE_CLIENT_TOKEN'),
'serverId' => env('BLACKFIRE_SERVER_ID'),
'serverToken' => env('BLACKFIRE_SERVER_TOKEN'),
],
];
BlackfiredHttpClient:
use Blackfire\Http\BlackfiredHttpClient
How can I help you explore Laravel packages today?