google-gemini-php/client
Community-maintained PHP API client for Google's Gemini AI API. Send text, image, video, and audio prompts, hold multi-turn chats, stream responses, call functions, generate images and speech, and manage files and cached content.
Requirements
2.8.0. Projects still on PHP 8.1 will stay on 2.7.x.php -v
composer require php:^8.2
Installation
composer require google-gemini-php/client:^2.8.0
Verify composer.json resolves to 2.8.0 and that CI uses PHP 8.2+.
First Request Initialize the client with your API key from Google AI Studio:
use Google\Gemini\Client;
$client = new Client(config('services.gemini.key'));
Basic Usage
$response = $client->generateText('What is Laravel?');
echo $response->getText();
Where to Look First
src/Client.php: core client wiring.src/Resources/: new API surfaces, including structured output, tools, and file search stores.src/Tools/: tool integrations (file search, maps, server-side tools).README.md: refreshed in 2.8.0 with current model names and examples.src/Exceptions/: error classes, including the new ErrorException behavior for streamed 5xx responses.Structured Output with JSON Schema Use JSON Schema for structured generation:
$response = $client->generativeModel('gemini-2.0-flash')
->withResponseSchema([
'type' => 'object',
'properties' => [
'title' => ['type' => 'string'],
'tags' => ['type' => 'array', 'items' => ['type' => 'string']],
],
'required' => ['title', 'tags'],
])
->generateContent('Summarize this article.');
Function Declarations with JSON Schema Define callable functions with typed schemas:
$model = $client->generativeModel('gemini-2.0-flash')
->withFunctionDeclaration(
name: 'get_weather',
description: 'Get the current weather for a city',
parameters: [
'type' => 'object',
'properties' => [
'city' => ['type' => 'string'],
],
'required' => ['city'],
],
);
$response = $model->generateContent('Weather in Paris?');
Multimodal Function Responses Return media from a function call:
$response = $model->generateContent(
new FunctionResponse(
name: 'get_weather',
response: ['temperature' => 21],
parts: [new Part(data: $imageBytes, mimeType: 'image/png')],
),
);
Server-Side Tool Invocations Use tools executed by Gemini itself:
$response = $client->generativeModel('gemini-2.0-flash')
->withTools([new GoogleSearch()])
->generateContent('Latest Laravel release?');
File Search Stores Upload and track files:
$operation = $fileSearchStore->importFile('files/abc123');
$operation = $fileSearchStore->getOperation($operation->name);
Note: file names with the files/ prefix are now accepted.
Per-Part Media Resolution and Image Size Control media resolution per part and image output size:
$part = new Part(data: $imageBytes, mimeType: 'image/png')
->withMediaResolution(MediaResolution::High);
$config = new ImageConfig();
$config->imageSize = '1024x1024';
Streaming Responses
$response = $client->generateText('Explain Laravel', ['stream' => true]);
foreach ($response->stream() as $chunk) {
echo $chunk->getText();
}
Failed streamed requests with a 5xx JSON error body now throw ErrorException, matching non-streamed requests.
Multi-Turn Chats
ClientFake::startChat() now supports multi-turn and streamed chats for tests:
ClientFake::fake();
$chat = $client->startChat();
$chat->sendMessage('Hello');
$chat->sendMessage('Continue');
Laravel Service Provider
$this->app->singleton(Client::class, fn ($app) =>
new Client(config('services.gemini.key'))
);
Queues for Long Operations
Use jobs for importFile() / getOperation() polling:
dispatch(new PollFileSearchOperation($operationName));
Testing with ClientFake
ClientFake::fake([
new GenerateContentResponse(...),
]);
$chat = $client->startChat();
$chat->sendMessage('Hi');
Error Handling
try {
$response = $client->generateText('Risky prompt');
} catch (Google\Gemini\Exception\ErrorException $e) {
// Stream and non-stream 5xx now converge here.
}
Response Metadata Inspect new metadata fields:
$response->responseId;
$response->modelStatus;
$response->finishMessage;
$response->urlContextMetadata;
$response->serviceTier;
PHP 8.2 Upgrade
2.8.0 drops PHP 8.1. Update composer.json, Docker images, and CI matrices together to avoid partial upgrades.Streamed Error Handling Changed
ErrorException instead of TransporterException. Update catch blocks and retry middleware.Chat History Shape Changed
streamSendMessage() now preserves thoughts, function calls, and tool calls as separate parts, including thoughtSignature. This fixes streamed function-call turns but $chat->history[$i]->parts may differ from before. Avoid strict assertions on chat history structure.Quick Accessor Error Messages
text() and parts() ValueError messages now include the finish or block reason. Update tests that assert exact exception messages.File Search Names
files/ prefix is now accepted in file names, so normalize names before storage to avoid duplicates.Usage Metadata
totalTokenCount is now accepted. Don’t assume the field always exists.Logprobs Token IDs
token_id field.Wrapped API Errors
Rate Limits and Quotas
API Key Exposure
.env and restrict key permissions in Google Cloud Console:
GEMINI_API_KEY=your_key_here
Verbose Logging
$client = new Client(config('services.gemini.key'), [
'debug' => true,
'logger' => new \Monolog\Logger('gemini'),
]);
Common Errors
| Error Class | Cause | Fix |
|---|---|---|
InvalidArgumentException |
Malformed prompt or schema | Validate prompt and JSON Schema |
Google\Gemini\Exception\AuthError |
Invalid API key | Check .env |
Google\Gemini\Exception\ErrorException |
5xx on stream or regular request | Retry with jitter |
Google\Gemini\Exception\ToolError |
Invalid tool configuration | Validate tool inputs |
ValueError |
text() / parts() called on incomplete response |
Inspect finish/block reason in message |
File Search Debugging
$operation = $fileSearchStore->getOperation($operationName);
logger()->debug('File search operation', $operation->toArray());
Schema Validation Validate schemas before sending:
if (!json_validate(json_encode($schema))) {
throw new \InvalidArgumentException('Invalid JSON Schema');
}
Custom Prompt Templates Extend the prompt abstraction for reusable formats:
class LaravelPrompt extends \Google\Gemini\Prompt
{
public function __construct(string $query)
{
parent::__construct('Laravel context: ' . $query);
}
}
Request Middleware
$client->setRequestMiddleware(function ($request) {
$request->setHeader('X-Custom-Header', 'value');
});
Async Processing
dispatch(new GenerateTextJob($prompt, $tools));
Custom Tools
class WeatherTool extends \Google\Gemini\Tool
{
public function __construct(string $location)
{
$this->setInput(['location' => $location]);
}
}
Server-Side Tool Composition Combine built-in and custom tools:
$model->withTools([
new GoogleSearch(),
new WeatherTool('Paris'),
]);
Testing Extensions
Add dedicated fake responses for multi-turn and streamed chats using ClientFake::startChat().
How can I help you explore Laravel packages today?