Guzzle
HTTP client library and web service framework for PHP. PSR-7 message interface compliant with asynchronous requests, middleware system, and MockHandler testing support. Adopted by major frameworks like Laravel and Symfony.
GitHub Overview
guzzle/guzzle
Guzzle, an extensible PHP HTTP client
Topics
Star History
Library
Guzzle
Overview
Guzzle is developed as "a comprehensive HTTP client library for PHP" - the most widely adopted HTTP client in the PHP ecosystem. With PSR (PHP Standard Recommendations) compliance, Promise-based asynchronous processing, plugin system, and extensive configuration options, it supports everything from simple APIs to enterprise-level complex requirements. As the standard adoption in major PHP frameworks like Symfony, Laravel, and WordPress, it has established itself as the de facto HTTP client standard in PHP development.
Details
Guzzle 2025 edition continues to evolve alongside PHP community maturity, delivering enterprise-grade HTTP client functionality with PHP 8.x support, enhanced type safety, and performance optimization. Supporting concurrent request processing, streaming, cookie management, proxy support, and detailed logging capabilities for various use cases including web scraping, API integration, and microservice communication. Through PSR-7 and PSR-18 compliant standardized HTTP message processing and a rich middleware ecosystem, it plays a crucial role as the HTTP communication foundation for PHP applications.
Key Features
- PSR Compliance: PSR-7 (HTTP Message) and PSR-18 (HTTP Client) standard support
- Concurrent Processing: Promise-based asynchronous and parallel request processing
- Middleware: Rich middleware ecosystem and extensibility
- Streaming: Efficient streaming processing for large data
- Proxy Support: Complete support for HTTP, HTTPS, and SOCKS proxies
- Framework Integration: Excellent integration with major PHP frameworks
Pros and Cons
Pros
- High reliability and proven track record in PHP developer community
- Standardized HTTP message processing through PSR compliance
- High performance through Promise-based asynchronous and parallel processing
- Extensibility through rich middleware ecosystem
- Flexible customization through detailed configuration options
- Excellent integration with Laravel, Symfony, and other major frameworks
Cons
- PHP-specific, not available in other language environments
- High learning cost due to rich functionality
- Complex for beginners due to many configuration options
- Requires Composer dependency management with many dependencies
- High memory usage, heavy for lightweight applications
- Limited HTTP/2 support with slower adoption of latest specifications
Reference Pages
Code Examples
Installation and Basic Setup
# Install Guzzle using Composer
composer require guzzlehttp/guzzle
# Guzzle Promise (for asynchronous processing)
composer require guzzlehttp/promises
# PSR-7 HTTP Message Implementation (recommended)
composer require guzzlehttp/psr7
# Version check
composer show guzzlehttp/guzzle
<?php
// Load Composer autoloader
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
Basic Requests (GET/POST/PUT/DELETE)
<?php
require_once 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class GuzzleBasicExample
{
private $client;
public function __construct()
{
// Basic client configuration
$this->client = new Client([
'base_uri' => 'https://api.example.com/',
'timeout' => 30.0,
'headers' => [
'User-Agent' => 'MyApp/1.0 (Guzzle PHP)',
'Accept' => 'application/json'
]
]);
}
// Basic GET request
public function basicGetRequest()
{
try {
$response = $this->client->request('GET', 'users', [
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
$statusCode = $response->getStatusCode();
$body = $response->getBody()->getContents();
$data = json_decode($body, true);
echo "Status: {$statusCode}\n";
echo "Response: " . print_r($data, true) . "\n";
return $data;
} catch (RequestException $e) {
echo "Request error: " . $e->getMessage() . "\n";
if ($e->hasResponse()) {
echo "Error response: " . $e->getResponse()->getBody() . "\n";
}
}
}
// GET request with query parameters
public function getWithQuery()
{
try {
$response = $this->client->request('GET', 'users', [
'query' => [
'page' => 1,
'limit' => 10,
'sort' => 'created_at',
'filter' => 'active'
],
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
$users = json_decode($response->getBody(), true);
echo "Search results: " . count($users) . " users found\n";
return $users;
} catch (RequestException $e) {
echo "Search error: " . $e->getMessage() . "\n";
}
}
// POST request (sending JSON)
public function postJsonRequest()
{
try {
$userData = [
'name' => 'John Doe',
'email' => '[email protected]',
'age' => 30,
'department' => 'Engineering'
];
$response = $this->client->request('POST', 'users', [
'json' => $userData, // Automatically converts to JSON
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
$newUser = json_decode($response->getBody(), true);
echo "User created: " . $newUser['id'] . "\n";
return $newUser;
} catch (RequestException $e) {
echo "Creation error: " . $e->getMessage() . "\n";
}
}
// PUT request (update)
public function putRequest()
{
try {
$updatedData = [
'name' => 'Jane Doe',
'email' => '[email protected]',
'department' => 'Product'
];
$response = $this->client->request('PUT', 'users/123', [
'json' => $updatedData,
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
if ($response->getStatusCode() === 200) {
echo "User updated successfully\n";
}
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Update error: " . $e->getMessage() . "\n";
}
}
// DELETE request
public function deleteRequest()
{
try {
$response = $this->client->request('DELETE', 'users/123', [
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
if ($response->getStatusCode() === 204) {
echo "User deleted successfully\n";
return true;
}
} catch (RequestException $e) {
echo "Delete error: " . $e->getMessage() . "\n";
return false;
}
}
// Form data submission
public function submitFormData()
{
try {
$response = $this->client->request('POST', 'login', [
'form_params' => [
'username' => 'testuser',
'password' => 'secret123',
'remember' => 'true'
]
]);
$loginResult = json_decode($response->getBody(), true);
echo "Login successful: " . $loginResult['token'] . "\n";
return $loginResult;
} catch (RequestException $e) {
echo "Login error: " . $e->getMessage() . "\n";
}
}
// Detailed response information retrieval
public function detailedResponse()
{
try {
$response = $this->client->request('GET', 'status');
echo "Status code: " . $response->getStatusCode() . "\n";
echo "Reason phrase: " . $response->getReasonPhrase() . "\n";
echo "Protocol version: " . $response->getProtocolVersion() . "\n";
echo "Headers: " . print_r($response->getHeaders(), true) . "\n";
echo "Content type: " . $response->getHeader('Content-Type')[0] . "\n";
echo "Content length: " . $response->getHeader('Content-Length')[0] . "\n";
} catch (RequestException $e) {
echo "Request error: " . $e->getMessage() . "\n";
}
}
// Raw response body handling
public function rawResponse()
{
try {
$response = $this->client->request('GET', 'raw-data', [
'stream' => true // Stream response
]);
$body = $response->getBody();
while (!$body->eof()) {
$chunk = $body->read(1024);
echo "Processing chunk: " . strlen($chunk) . " bytes\n";
// Process chunk data
}
} catch (RequestException $e) {
echo "Stream error: " . $e->getMessage() . "\n";
}
}
}
// Usage example
$example = new GuzzleBasicExample();
$example->basicGetRequest();
$example->getWithQuery();
$example->postJsonRequest();
Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)
<?php
// Advanced client configuration
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Exception\RequestException;
class GuzzleAdvancedExample
{
private $client;
public function __construct()
{
// Create handler stack
$stack = HandlerStack::create();
// Add middleware
$stack->push(Middleware::log(
new \Monolog\Logger('guzzle'),
new \Monolog\Formatter\LineFormatter()
));
$this->client = new Client([
'base_uri' => 'https://api.example.com/',
'timeout' => 30.0,
'handler' => $stack,
'headers' => [
'User-Agent' => 'MyApp/1.0 (Guzzle PHP)',
'Accept' => 'application/json',
'Accept-Language' => 'en-US,ja-JP;q=0.9'
],
'cookies' => true, // Enable cookie jar
'allow_redirects' => [
'max' => 3,
'strict' => true,
'referer' => true,
'protocols' => ['http', 'https'],
'track_redirects' => true
]
]);
}
// Custom headers and authentication
public function advancedHeaders()
{
try {
$response = $this->client->request('GET', 'protected', [
'headers' => [
'Authorization' => 'Bearer your-jwt-token',
'X-API-Version' => 'v2',
'X-Request-ID' => $this->generateRequestId(),
'X-Client-Info' => 'PHP/' . PHP_VERSION,
'Cache-Control' => 'no-cache'
],
'timeout' => 10.0,
'read_timeout' => 15.0,
'connect_timeout' => 5.0
]);
echo "Protected resource accessed successfully\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
if ($e->hasResponse()) {
$status = $e->getResponse()->getStatusCode();
echo "Authentication error: HTTP {$status}\n";
} else {
echo "Connection error: " . $e->getMessage() . "\n";
}
}
}
// Basic authentication
public function basicAuth()
{
try {
$response = $this->client->request('GET', 'basic-auth', [
'auth' => ['username', 'password'] // Basic auth
]);
echo "Basic auth success\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Authentication failed: " . $e->getMessage() . "\n";
}
}
// Digest authentication
public function digestAuth()
{
try {
$response = $this->client->request('GET', 'digest-auth', [
'auth' => ['username', 'password', 'digest']
]);
echo "Digest auth success\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Digest auth failed: " . $e->getMessage() . "\n";
}
}
// Proxy configuration
public function proxyRequest()
{
try {
$response = $this->client->request('GET', 'data', [
'proxy' => [
'http' => 'http://proxy.example.com:8080',
'https' => 'http://proxy.example.com:8080',
'no' => ['.example.com', 'localhost']
],
'headers' => [
'User-Agent' => 'MyApp via Proxy'
]
]);
echo "Response via proxy received\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Proxy error: " . $e->getMessage() . "\n";
}
}
// SSL/TLS configuration
public function sslConfiguration()
{
try {
$response = $this->client->request('GET', 'data', [
'verify' => '/path/to/ca-bundle.crt', // CA certificate
'cert' => ['/path/to/client.pem', 'password'], // Client certificate
'ssl_key' => ['/path/to/private.key', 'password'], // Private key
'version' => CURL_HTTP_VERSION_2_0, // Force HTTP/2
'curl' => [
CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
CURLOPT_SSL_CIPHER_LIST => 'ECDHE-RSA-AES256-GCM-SHA384'
]
]);
echo "SSL communication successful\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "SSL configuration error: " . $e->getMessage() . "\n";
}
}
// Cookie handling
public function cookieHandling()
{
try {
// Create cookie jar
$cookieJar = new \GuzzleHttp\Cookie\CookieJar();
$response = $this->client->request('GET', 'session-data', [
'cookies' => $cookieJar
]);
echo "Request with cookies completed\n";
// Display cookies
foreach ($cookieJar as $cookie) {
echo "Cookie: {$cookie->getName()} = {$cookie->getValue()}\n";
}
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Cookie handling error: " . $e->getMessage() . "\n";
}
}
// Custom request options
public function customRequestOptions()
{
try {
$response = $this->client->request('POST', 'complex-endpoint', [
'multipart' => [
[
'name' => 'field1',
'contents' => 'value1'
],
[
'name' => 'file',
'contents' => fopen('/path/to/file.txt', 'r'),
'filename' => 'upload.txt',
'headers' => ['Content-Type' => 'text/plain']
]
],
'progress' => function($downloadTotal, $downloadedBytes, $uploadTotal, $uploadedBytes) {
if ($uploadTotal > 0) {
$percent = round(($uploadedBytes / $uploadTotal) * 100);
echo "Upload progress: {$percent}%\n";
}
},
'on_headers' => function(ResponseInterface $response) {
echo "Response headers received\n";
if ($response->getStatusCode() !== 200) {
throw new \Exception('Unexpected status code');
}
}
]);
echo "Complex request completed\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Complex request error: " . $e->getMessage() . "\n";
}
}
private function generateRequestId()
{
return 'req-' . time() . '-' . bin2hex(random_bytes(8));
}
}
// Usage example
$example = new GuzzleAdvancedExample();
$example->advancedHeaders();
$example->basicAuth();
$example->proxyRequest();
Error Handling and Retry Functionality
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
class GuzzleErrorHandling
{
private $client;
public function __construct()
{
// Create handler stack with retry middleware
$stack = HandlerStack::create();
$stack->push(Middleware::retry($this->retryDecider(), $this->retryDelay()));
$this->client = new Client([
'base_uri' => 'https://api.example.com/',
'timeout' => 30.0,
'handler' => $stack,
'http_errors' => true // Enable HTTP error exceptions
]);
}
// Comprehensive error handling
public function comprehensiveErrorHandling()
{
try {
$response = $this->client->request('GET', 'users', [
'timeout' => 10.0,
'headers' => [
'Authorization' => 'Bearer your-jwt-token'
]
]);
return json_decode($response->getBody(), true);
} catch (ClientException $e) {
// 4xx errors
$response = $e->getResponse();
$statusCode = $response->getStatusCode();
$errorBody = $response->getBody()->getContents();
echo "Client Error: {$statusCode}\n";
switch ($statusCode) {
case 400:
echo "Bad Request: Please check request parameters\n";
break;
case 401:
echo "Unauthorized: Invalid authentication credentials\n";
// Trigger token refresh
return $this->refreshTokenAndRetry();
case 403:
echo "Forbidden: Insufficient permissions\n";
break;
case 404:
echo "Not Found: Resource does not exist\n";
break;
case 429:
$retryAfter = $response->getHeader('Retry-After')[0] ?? null;
echo "Rate Limited: Please try again later\n";
if ($retryAfter) {
echo "Retry available after: {$retryAfter} seconds\n";
sleep((int)$retryAfter);
return $this->comprehensiveErrorHandling(); // Retry
}
break;
default:
echo "Error details: {$errorBody}\n";
}
} catch (ServerException $e) {
// 5xx errors
$response = $e->getResponse();
$statusCode = $response->getStatusCode();
echo "Server Error: {$statusCode}\n";
switch ($statusCode) {
case 500:
echo "Internal Server Error: Server-side issue\n";
break;
case 502:
echo "Bad Gateway: Server temporarily unavailable\n";
break;
case 503:
echo "Service Unavailable: Server overloaded\n";
break;
case 504:
echo "Gateway Timeout: Request timeout\n";
break;
}
} catch (ConnectException $e) {
// Network connection errors
echo "Network error: " . $e->getMessage() . "\n";
echo "Request: " . $e->getRequest()->getUri() . "\n";
} catch (RequestException $e) {
// Other request errors
echo "Request error: " . $e->getMessage() . "\n";
if ($e->hasResponse()) {
echo "Response: " . $e->getResponse()->getBody() . "\n";
}
} catch (\Exception $e) {
// General errors
echo "General error: " . $e->getMessage() . "\n";
}
return null;
}
// Retry decision logic
private function retryDecider()
{
return function (
$retries,
RequestInterface $request,
ResponseInterface $response = null,
RequestException $exception = null
) {
// Limit retry attempts
if ($retries >= 3) {
return false;
}
// Retry on connection errors
if ($exception instanceof ConnectException) {
return true;
}
// Retry on specific HTTP status codes
if ($response) {
$statusCode = $response->getStatusCode();
return in_array($statusCode, [408, 429, 500, 502, 503, 504]);
}
return false;
};
}
// Retry delay (exponential backoff)
private function retryDelay()
{
return function ($numberOfRetries) {
return 1000 * pow(2, $numberOfRetries); // 1s, 2s, 4s...
};
}
// Manual retry strategy
public function manualRetryStrategy()
{
$maxRetries = 3;
$baseDelay = 1000; // 1 second (in milliseconds)
for ($attempt = 0; $attempt <= $maxRetries; $attempt++) {
try {
$response = $this->client->request('GET', 'unstable-endpoint', [
'timeout' => 10.0
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
$isLastAttempt = $attempt === $maxRetries;
if ($isLastAttempt) {
echo "Maximum retry attempts reached: " . $e->getMessage() . "\n";
throw $e;
}
// Check if error should be retried
$shouldRetry = $this->shouldRetryException($e);
if (!$shouldRetry) {
echo "Non-retryable error: " . $e->getMessage() . "\n";
throw $e;
}
// Exponential backoff
$delay = $baseDelay * pow(2, $attempt);
echo "Retry {$attempt}/{$maxRetries} - retrying in {$delay}ms\n";
usleep($delay * 1000); // Convert to microseconds
}
}
}
// Determine if exception should be retried
private function shouldRetryException(RequestException $e)
{
// Connection errors should be retried
if ($e instanceof ConnectException) {
return true;
}
// Specific HTTP status codes should be retried
if ($e->hasResponse()) {
$statusCode = $e->getResponse()->getStatusCode();
return in_array($statusCode, [408, 429, 500, 502, 503, 504]);
}
return false;
}
// Progressive failure recovery (fallback endpoints)
public function progressiveRecovery()
{
$endpoints = [
'https://primary-api.example.com/data',
'https://backup-api.example.com/data',
'https://fallback-api.example.com/data'
];
foreach ($endpoints as $index => $endpoint) {
try {
echo "Attempt " . ($index + 1) . ": {$endpoint}\n";
$response = $this->client->request('GET', $endpoint, [
'timeout' => 5.0 + ($index * 2), // Gradually increase timeout
'base_uri' => '' // Override base URI
]);
echo "Success with endpoint " . ($index + 1) . "\n";
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
echo "Endpoint " . ($index + 1) . " failed: " . $e->getMessage() . "\n";
if ($index === count($endpoints) - 1) {
echo "All endpoints failed\n";
throw new \Exception('All endpoints failed');
}
}
}
}
// Token refresh functionality
private function refreshTokenAndRetry()
{
try {
// Implement token refresh logic
$refreshResponse = $this->client->request('POST', 'auth/refresh', [
'json' => ['refresh_token' => 'stored-refresh-token']
]);
$tokens = json_decode($refreshResponse->getBody(), true);
// Store new tokens
echo "Token refreshed successfully\n";
// Retry original request with new token
return $this->client->request('GET', 'users', [
'headers' => [
'Authorization' => 'Bearer ' . $tokens['access_token']
]
]);
} catch (RequestException $e) {
echo "Token refresh failed: " . $e->getMessage() . "\n";
throw $e;
}
}
}
// Usage example
$errorHandler = new GuzzleErrorHandling();
$result = $errorHandler->comprehensiveErrorHandling();
$result2 = $errorHandler->manualRetryStrategy();
$result3 = $errorHandler->progressiveRecovery();
Concurrent Processing and Asynchronous Requests
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
class GuzzleConcurrentExample
{
private $client;
public function __construct()
{
$this->client = new Client([
'base_uri' => 'https://api.example.com/',
'timeout' => 30.0,
'headers' => [
'User-Agent' => 'MyApp/1.0 (Guzzle PHP)',
'Accept' => 'application/json'
]
]);
}
// Basic parallel requests using Promises
public function basicParallelRequests()
{
$startTime = microtime(true);
try {
// Create promises for multiple requests
$promises = [
'users' => $this->client->getAsync('users'),
'posts' => $this->client->getAsync('posts'),
'comments' => $this->client->getAsync('comments'),
'categories' => $this->client->getAsync('categories')
];
// Wait for all promises to complete
$responses = Promise\settle($promises)->wait();
$endTime = microtime(true);
echo "Parallel execution time: " . round(($endTime - $startTime) * 1000, 2) . "ms\n";
$results = [];
foreach ($responses as $key => $response) {
if ($response['state'] === 'fulfilled') {
$results[$key] = json_decode($response['value']->getBody(), true);
echo "{$key}: Success (" . count($results[$key]) . " items)\n";
} else {
echo "{$key}: Failed - " . $response['reason']->getMessage() . "\n";
}
}
return $results;
} catch (\Exception $e) {
echo "Parallel request error: " . $e->getMessage() . "\n";
return [];
}
}
// Concurrent requests with partial failure tolerance
public function concurrentWithPartialFailure()
{
$endpoints = [
'endpoint1' => 'users',
'endpoint2' => 'posts',
'endpoint3' => 'comments',
'unreliable' => 'unreliable-endpoint'
];
$promises = [];
foreach ($endpoints as $key => $endpoint) {
$promises[$key] = $this->client->getAsync($endpoint, [
'timeout' => 5.0
]);
}
$responses = Promise\settle($promises)->wait();
$successful = [];
$failed = [];
foreach ($responses as $key => $response) {
if ($response['state'] === 'fulfilled') {
$successful[$key] = json_decode($response['value']->getBody(), true);
} else {
$failed[$key] = $response['reason']->getMessage();
}
}
echo "Success: " . count($successful) . ", Failed: " . count($failed) . "\n";
if (!empty($failed)) {
echo "Failed endpoints: " . print_r($failed, true) . "\n";
}
return ['successful' => $successful, 'failed' => $failed];
}
// Sequential data fetching with pagination
public function fetchAllPages()
{
$allData = [];
$page = 1;
$hasMore = true;
while ($hasMore) {
try {
$response = $this->client->request('GET', 'paginated-data', [
'query' => [
'page' => $page,
'limit' => 20
],
'timeout' => 10.0
]);
$pageData = json_decode($response->getBody(), true);
$allData = array_merge($allData, $pageData['items']);
$hasMore = $pageData['has_more'];
$page++;
echo "Page {$page} completed: " . count($pageData['items']) . " items\n";
// Wait to reduce API load
if ($hasMore) {
usleep(200000); // 200ms wait
}
} catch (RequestException $e) {
echo "Page {$page} fetch error: " . $e->getMessage() . "\n";
break;
}
}
echo "Total " . count($allData) . " items fetched\n";
return $allData;
}
// Parallel pagination (high-speed data fetching)
public function parallelPagination()
{
try {
// Get total pages from first page
$firstPageResponse = $this->client->request('GET', 'paginated-data', [
'query' => ['page' => 1, 'limit' => 20]
]);
$firstPageData = json_decode($firstPageResponse->getBody(), true);
$totalPages = $firstPageData['total_pages'];
$allData = $firstPageData['items'];
if ($totalPages > 1) {
// Create promises for remaining pages
$promises = [];
for ($page = 2; $page <= $totalPages; $page++) {
$promises["page_{$page}"] = $this->client->getAsync('paginated-data', [
'query' => ['page' => $page, 'limit' => 20],
'timeout' => 10.0
]);
}
$responses = Promise\settle($promises)->wait();
foreach ($responses as $key => $response) {
if ($response['state'] === 'fulfilled') {
$pageData = json_decode($response['value']->getBody(), true);
$allData = array_merge($allData, $pageData['items']);
} else {
echo "{$key} failed: " . $response['reason']->getMessage() . "\n";
}
}
}
echo "Parallel fetch completed: " . count($allData) . " items\n";
return $allData;
} catch (RequestException $e) {
echo "Parallel pagination error: " . $e->getMessage() . "\n";
return [];
}
}
// Pool for handling large numbers of requests
public function poolRequests()
{
$urls = [];
for ($i = 1; $i <= 100; $i++) {
$urls[] = "items/{$i}";
}
$requests = function ($urls) {
foreach ($urls as $url) {
yield new Request('GET', $url);
}
};
$pool = new Pool($this->client, $requests($urls), [
'concurrency' => 5, // Maximum concurrent requests
'fulfilled' => function ($response, $index) {
echo "Request {$index} completed\n";
// Process successful response
},
'rejected' => function ($reason, $index) {
echo "Request {$index} failed: " . $reason->getMessage() . "\n";
// Handle failed request
},
]);
// Start pool execution
$promise = $pool->promise();
$promise->wait();
echo "Pool processing completed\n";
}
// Rate-limited sequential execution
public function rateLimitedRequests($urls, $requestsPerSecond = 5)
{
$interval = 1000000 / $requestsPerSecond; // Microseconds
$results = [];
foreach ($urls as $index => $url) {
$startTime = microtime(true);
try {
$response = $this->client->request('GET', $url, [
'timeout' => 5.0
]);
$results[] = [
'url' => $url,
'success' => true,
'data' => json_decode($response->getBody(), true)
];
echo ($index + 1) . "/" . count($urls) . " completed: {$url}\n";
} catch (RequestException $e) {
$results[] = [
'url' => $url,
'success' => false,
'error' => $e->getMessage()
];
echo ($index + 1) . "/" . count($urls) . " failed: {$url}\n";
}
// Rate limiting wait
if ($index < count($urls) - 1) {
$elapsed = (microtime(true) - $startTime) * 1000000;
$waitTime = max(0, $interval - $elapsed);
if ($waitTime > 0) {
usleep((int)$waitTime);
}
}
}
$successCount = count(array_filter($results, function($r) { return $r['success']; }));
echo "Processing completed: {$successCount}/" . count($urls) . " successful\n";
return $results;
}
// Streaming data processing
public function streamingProcessing()
{
try {
$response = $this->client->request('GET', 'large-dataset', [
'stream' => true,
'timeout' => 60.0
]);
$body = $response->getBody();
$buffer = '';
$processedLines = 0;
while (!$body->eof()) {
$chunk = $body->read(8192); // Read 8KB chunks
$buffer .= $chunk;
// Process complete lines
while (($newlinePos = strpos($buffer, "\n")) !== false) {
$line = substr($buffer, 0, $newlinePos);
$buffer = substr($buffer, $newlinePos + 1);
// Process individual line
$this->processDataLine($line);
$processedLines++;
if ($processedLines % 1000 === 0) {
echo "Processed {$processedLines} lines\n";
}
}
}
echo "Streaming processing completed: {$processedLines} lines\n";
} catch (RequestException $e) {
echo "Streaming error: " . $e->getMessage() . "\n";
}
}
private function processDataLine($line)
{
// Individual line processing logic
$data = json_decode($line, true);
if ($data) {
// Process data
}
}
}
// Usage example
$concurrent = new GuzzleConcurrentExample();
$concurrent->basicParallelRequests();
$concurrent->concurrentWithPartialFailure();
$concurrent->parallelPagination();
Framework Integration and Practical Examples
<?php
// Laravel integration example
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
class ApiService
{
private $client;
private $baseUrl;
private $apiKey;
public function __construct()
{
$this->baseUrl = config('services.api.base_url');
$this->apiKey = config('services.api.key');
$this->client = new Client([
'base_uri' => $this->baseUrl,
'timeout' => 30.0,
'headers' => [
'Authorization' => 'Bearer ' . $this->apiKey,
'Accept' => 'application/json',
'User-Agent' => 'Laravel/' . app()->version() . ' (Guzzle)'
]
]);
}
// Get users with caching
public function getUsers($page = 1, $limit = 20)
{
$cacheKey = "users.page.{$page}.limit.{$limit}";
return Cache::remember($cacheKey, 300, function () use ($page, $limit) {
try {
$response = $this->client->request('GET', 'users', [
'query' => [
'page' => $page,
'limit' => $limit
]
]);
$data = json_decode($response->getBody(), true);
Log::info('Users fetched successfully', ['page' => $page, 'count' => count($data)]);
return [
'data' => $data,
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => (int)$response->getHeader('X-Total-Count')[0] ?? 0
]
];
} catch (RequestException $e) {
Log::error('Failed to fetch users', [
'page' => $page,
'error' => $e->getMessage()
]);
throw $e;
}
});
}
// Create user with validation
public function createUser(array $userData)
{
try {
$response = $this->client->request('POST', 'users', [
'json' => $userData,
'headers' => [
'X-Request-ID' => $this->generateRequestId()
]
]);
$newUser = json_decode($response->getBody(), true);
Log::info('User created successfully', ['user_id' => $newUser['id']]);
// Clear users cache
Cache::tags(['users'])->flush();
return $newUser;
} catch (RequestException $e) {
Log::error('Failed to create user', [
'data' => $userData,
'error' => $e->getMessage()
]);
throw $e;
}
}
private function generateRequestId()
{
return 'laravel-' . time() . '-' . bin2hex(random_bytes(8));
}
}
// Symfony integration example
namespace App\Service;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Cache\CacheInterface;
class ApiClient
{
private $client;
private $logger;
private $cache;
public function __construct(LoggerInterface $logger, CacheInterface $cache)
{
$this->logger = $logger;
$this->cache = $cache;
$this->client = new Client([
'base_uri' => $_ENV['API_BASE_URL'],
'timeout' => 30.0,
'headers' => [
'Authorization' => 'Bearer ' . $_ENV['API_TOKEN'],
'Accept' => 'application/json'
]
]);
}
public function fetchData($endpoint, $cacheTime = 300)
{
$cacheKey = 'api_data_' . md5($endpoint);
return $this->cache->get($cacheKey, function () use ($endpoint) {
try {
$response = $this->client->request('GET', $endpoint);
$data = json_decode($response->getBody(), true);
$this->logger->info('API data fetched', ['endpoint' => $endpoint]);
return $data;
} catch (RequestException $e) {
$this->logger->error('API request failed', [
'endpoint' => $endpoint,
'error' => $e->getMessage()
]);
throw $e;
}
}, $cacheTime);
}
}
// WordPress plugin integration example
class WP_API_Client
{
private $client;
public function __construct()
{
$this->client = new Client([
'base_uri' => get_option('api_base_url'),
'timeout' => 30.0,
'headers' => [
'Authorization' => 'Bearer ' . get_option('api_token'),
'Accept' => 'application/json'
]
]);
}
public function sync_posts()
{
try {
$response = $this->client->request('GET', 'posts', [
'query' => [
'limit' => 50,
'updated_since' => get_option('last_sync_time')
]
]);
$posts = json_decode($response->getBody(), true);
foreach ($posts as $postData) {
$this->create_or_update_post($postData);
}
update_option('last_sync_time', current_time('mysql'));
wp_die('Posts synced successfully: ' . count($posts) . ' posts');
} catch (RequestException $e) {
wp_die('Sync failed: ' . $e->getMessage());
}
}
private function create_or_update_post($postData)
{
$existing_post = get_posts([
'meta_key' => 'external_id',
'meta_value' => $postData['id'],
'post_type' => 'post',
'numberposts' => 1
]);
$post_args = [
'post_title' => $postData['title'],
'post_content' => $postData['content'],
'post_status' => 'publish',
'post_type' => 'post'
];
if (!empty($existing_post)) {
$post_args['ID'] = $existing_post[0]->ID;
wp_update_post($post_args);
} else {
$post_id = wp_insert_post($post_args);
update_post_meta($post_id, 'external_id', $postData['id']);
}
}
}
// Generic PHP application example
class GenericApiClient
{
private $client;
private $config;
public function __construct($config)
{
$this->config = $config;
$this->client = new Client([
'base_uri' => $config['base_url'],
'timeout' => $config['timeout'] ?? 30.0,
'headers' => [
'Authorization' => 'Bearer ' . $config['api_key'],
'Accept' => 'application/json',
'User-Agent' => $config['user_agent'] ?? 'Generic PHP Client'
]
]);
}
// Generic CRUD operations
public function get($endpoint, $params = [])
{
try {
$response = $this->client->request('GET', $endpoint, [
'query' => $params
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
$this->handleError($e, 'GET', $endpoint);
}
}
public function post($endpoint, $data = [])
{
try {
$response = $this->client->request('POST', $endpoint, [
'json' => $data
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
$this->handleError($e, 'POST', $endpoint);
}
}
public function put($endpoint, $data = [])
{
try {
$response = $this->client->request('PUT', $endpoint, [
'json' => $data
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
$this->handleError($e, 'PUT', $endpoint);
}
}
public function delete($endpoint)
{
try {
$response = $this->client->request('DELETE', $endpoint);
return $response->getStatusCode() === 204;
} catch (RequestException $e) {
$this->handleError($e, 'DELETE', $endpoint);
}
}
// File upload
public function uploadFile($endpoint, $filePath, $additionalData = [])
{
try {
$multipart = [
[
'name' => 'file',
'contents' => fopen($filePath, 'r'),
'filename' => basename($filePath)
]
];
foreach ($additionalData as $key => $value) {
$multipart[] = [
'name' => $key,
'contents' => $value
];
}
$response = $this->client->request('POST', $endpoint, [
'multipart' => $multipart,
'progress' => function($downloadTotal, $downloadedBytes, $uploadTotal, $uploadedBytes) {
if ($uploadTotal > 0) {
$percent = round(($uploadedBytes / $uploadTotal) * 100);
echo "Upload progress: {$percent}%\r";
}
}
]);
return json_decode($response->getBody(), true);
} catch (RequestException $e) {
$this->handleError($e, 'UPLOAD', $endpoint);
}
}
private function handleError(RequestException $e, $method, $endpoint)
{
$message = "API Error [{$method} {$endpoint}]: " . $e->getMessage();
if ($e->hasResponse()) {
$response = $e->getResponse();
$message .= " (HTTP " . $response->getStatusCode() . ")";
$message .= " Response: " . $response->getBody();
}
if ($this->config['debug'] ?? false) {
echo $message . "\n";
}
throw new \Exception($message);
}
}
// Usage example
$config = [
'base_url' => 'https://api.example.com/',
'api_key' => 'your-api-key',
'timeout' => 30.0,
'user_agent' => 'MyApp/1.0',
'debug' => true
];
$apiClient = new GenericApiClient($config);
$users = $apiClient->get('users', ['page' => 1]);
$newUser = $apiClient->post('users', ['name' => 'John Doe', 'email' => '[email protected]']);