PHPackages                             kiwilan/php-http-pool - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. kiwilan/php-http-pool

ActiveLibrary[HTTP &amp; Networking](/categories/http)

kiwilan/php-http-pool
=====================

PHP package with easy-to-use GuzzleHttp pool wrapper to make concurrent requests.

0.3.4(2y ago)22.7k↓100%1[1 PRs](https://github.com/kiwilan/php-http-pool/pulls)1MITPHPPHP ^8.1

Since Aug 6Pushed 1y ago1 watchersCompare

[ Source](https://github.com/kiwilan/php-http-pool)[ Packagist](https://packagist.org/packages/kiwilan/php-http-pool)[ Docs](https://github.com/kiwilan/php-http-pool)[ GitHub Sponsors](https://github.com/kiwilan)[ RSS](/packages/kiwilan-php-http-pool/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (6)Versions (16)Used By (1)

PHP HTTP Pool
=============

[](#php-http-pool)

[![Banner with cards catalog picture in background and PHP XML Reader title](https://raw.githubusercontent.com/kiwilan/php-http-pool/main/docs/banner.jpg)](https://raw.githubusercontent.com/kiwilan/php-http-pool/main/docs/banner.jpg)

[![php](https://camo.githubusercontent.com/2d44ab343cf5a2aab849b6954ee31dd09ba1f1f11bf0f168ccd08e186ec060b1/68747470733a2f2f696d672e736869656c64732e696f2f7374617469632f76313f7374796c653d666c6174266c6162656c3d504850266d6573736167653d76382e3126636f6c6f723d373737424234266c6f676f3d706870266c6f676f436f6c6f723d666666666666266c6162656c436f6c6f723d313831383162)](https://www.php.net/)[![version](https://camo.githubusercontent.com/c8057c75d3ea8b705aa1474d71a8e665eeaf94c3ef3dd608c673ff133a299e7a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b6977696c616e2f7068702d687474702d706f6f6c2e7376673f7374796c653d666c617426636f6c6f72413d31383138314226636f6c6f72423d373737424234)](https://packagist.org/packages/kiwilan/php-http-pool)[![downloads](https://camo.githubusercontent.com/ac87cd32934cfe03d7c7a7399e20a89581975ccb78226d7bb224509a3424a049/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b6977696c616e2f7068702d687474702d706f6f6c2e7376673f7374796c653d666c617426636f6c6f72413d31383138314226636f6c6f72423d373737424234)](https://packagist.org/packages/kiwilan/php-http-pool)[![license](https://camo.githubusercontent.com/8d79617e2647799ad23def89163f0295a824cd4228fdbbcf5e1ae50f24419db6/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6b6977696c616e2f7068702d687474702d706f6f6c2e7376673f7374796c653d666c617426636f6c6f72413d31383138314226636f6c6f72423d373737424234)](https://github.com/kiwilan/php-http-pool/blob/main/README.md)[![tests](https://camo.githubusercontent.com/769e0128afb0cd184e98ed6843644e1b08e960933ebc466fd3f10cce3441342f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6b6977696c616e2f7068702d687474702d706f6f6c2f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c617426636f6c6f72413d313831383142)](https://packagist.org/packages/kiwilan/php-http-pool)[![codecov](https://camo.githubusercontent.com/f25d19e69dd85ba258b9218b9078391733ef266a6f0ea54bb283d977ca58ce85/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f67682f6b6977696c616e2f7068702d687474702d706f6f6c2f6d61696e3f7374796c653d666c617426636f6c6f72413d31383138314226636f6c6f72423d373737424234)](https://codecov.io/gh/kiwilan/php-http-pool)

PHP package with easy-to-use [`GuzzleHttp`](https://docs.guzzlephp.org/en/stable/quickstart.html) pool wrapper, works with `GuzzleHttp\Pool` and `GuzzleHttp\Client` to make concurrent requests.

Note

I love `GuzzleHttp\Pool`, but I would to build a wrapper to make it easier to use and Laravel `Http\Pool` is cool but not flexible enough for me. So `HttpPool` allow you to send an `array` or a `Collection` of requests and get a `Collection` of with all `GuzzleHttp` features and more.

Built to be more flexible that Laravel [`Http`](https://laravel.com/docs/10.x/http-client#customizing-concurrent-requests) Pool, if Laravel Pool is perfect for you, keep using it.

Features
--------

[](#features)

- 🚚 Works with very big pool of requests: requests chunked to avoid memory peak
- 🗂️ Keep identifier of each request: easy to put response into original item (in case of `Collection` of `Model` with Laravel, for example)
- 📦 `HttpPoolResponse` wrapper with some features to improve DX: original ID, body, metadata...
- 🏡 Keep original `GuzzleHttp` response in `HttpPoolResponse`: you're in home
- 🚨 Allow handle memory peak: if you have a lot of requests
- 🗃️ Works with simple arrays, with associative arrays, with array of objects, with Laravel [`Collection`](https://laravel.com/docs/10.x/collections): just define where to get identifier and URL
- 💬 Optional console output: you can disable it if you don't want to see progress
- 🚀 Works with any PHP frameworks, `Illuminate\Support\Collection` is a dependency but you can use it without Laravel, `toArray()` method is available after pool execution if you don't want to use `Collection`

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require kiwilan/php-http-pool
```

Usage
-----

[](#usage)

### Input

[](#input)

When you want to use `HttpPool`, you have to pass an input, it could be: a simple array, an associative array, a Laravel `Collection` or an array of objects.

#### With simple array

[](#with-simple-array)

```
use Kiwilan\HttpPool\HttpPool;

// Key is the identifier, value is the URL
// Array could be associative or not
$urls = [
  2 => 'https://jsonplaceholder.typicode.com/posts',
  5 => 'https://jsonplaceholder.typicode.com/comments',
  10 => 'https://jsonplaceholder.typicode.com/albums',
  16 => 'https://jsonplaceholder.typicode.com/photos',
  24 => 'https://jsonplaceholder.typicode.com/todos',
];

// Create a pool with an array of URLs and some options
$pool = HttpPool::make($urls)
  ->setMaxCurlHandles(100)
  ->setMaxRedirects(10)
  ->setTimeout(30)
  ->setConcurrencyMaximum(5)
  ->setPoolLimit(250)
  ->setHeaders([
    'User-Agent' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
  ])
;

// Get original requests converted for `HttpPool`
$requests = $pool->getRequests();
$requestCount = $pool->getRequestCount();

// Execute pool
$res = $pool->execute();

// Get responses
$responses = $res->getResponses();

// Get responses as array
$responsesArray = $res->toArray();

// Get only fullfilled responses
$fullfilled = $res->getFullfilledResponses();

// Get only rejected responses
$rejected = $res->getRejectedResponses();

// Counts
$fullfilledCount = $res->getFullfilledCount();
$rejectedCount = $res->getRejectedCount();

// Get execution time
$executionTime = $res->getExecutionTime();

// Get pool instance
$pool = $res->getPool();
```

#### Associative array

[](#associative-array)

Warning

Identifier and URL have to not be nested.

```
use Kiwilan\HttpPool\HttpPool;

$urls = [
  [
      'uuid' => 100,
      'name' => 'posts',
      'api' => 'https://jsonplaceholder.typicode.com/posts',
  ],
  [
      'uuid' => 125,
      'name' => 'comments',
      'api' => 'https://jsonplaceholder.typicode.com/comments',
  ],
];

$res = HttpPool::make($urls)
  ->setIdentifierKey('uuid') // Default is 'id'
  ->setUrlKey('api') // Default is 'url'
  ->execute()
;

$first = $res->getResponses()->first(); // HttpPoolResponse
$first->getId(); // 100, 125
```

#### Laravel models

[](#laravel-models)

Take a Laravel model collection and send requests with `HttpPool`. Here `Book` is a Laravel model, we assume that `Book` has an `id` attribute and a `google_book_api` attribute.

```
use App\Models\Book;
use Kiwilan\HttpPool\HttpPool;

$books = Book::all(); // `Illuminate\Support\Collection` of `Book`

$pool = HttpPool::make($books)
  ->setUrlKey('google_book_api') // Default is 'url'
  ->execute()
;

$first = $pool->getResponses()->first(); // HttpPoolResponse
$first->getId(); // 1, 2, 3... (Book ID)
```

#### Array of objects

[](#array-of-objects)

Here we take an array of objects, we assume that each object has an `uuid` attribute and an `url` attribute. You can just define getters like `getUuid()` and `getUrl()` or you can use `public` attributes, it's up to you.

Warning

If attributes are `private` or `protected`, you have to define getters with logic names: `getUuid()` and `getUrl()`. You can use `uuid()` and `url()` too as getters. But here, if you create a getter `getBookUuid()`, it will not work.

```
use Kiwilan\HttpPool\HttpPool;

$urls = [
  new Book(
    uuid: 100,
    name: 'posts',
    url: 'https://jsonplaceholder.typicode.com/posts',
  ),
  new Book(
    uuid: 125,
    name: 'comments',
    url: 'https://jsonplaceholder.typicode.com/comments',
  ),
];

$res = HttpPool::make($urls)
  ->setIdentifierKey('uuid') // Default is 'id'
  ->execute()
;

$first = $res->getResponses()->first(); // HttpPoolResponse
$first->getId(); // 100, 125
```

### Execution

[](#execution)

To execute pool, you can use `execute()` method.

```
use Kiwilan\HttpPool\HttpPool;

$pool = HttpPool::make($urls);
$res = $pool->execute();
```

`execute()` method returns a `HttpPoolFullfilled` object. You can get pool with `getPool()` method.

```
use Kiwilan\HttpPool\HttpPool;

$pool = HttpPool::make($urls);
$res = $pool->execute();

$pool = $res->getPool();
```

In `HttpPoolFullfilled` object, you can get responses and more features. All methods `getResponses()`,`getFullfilled()`, `getRejected()` are `Illuminate\Support\Collection` of `HttpPoolResponse`.

```
use Kiwilan\HttpPool\HttpPool;

$pool = HttpPool::make($urls);
$res = $pool->execute();

// Get all responses (fullfilled and rejected)
$responses = $res->getResponses();

// Get only fullfilled responses
$fullfilled = $res->getFullfilled();

// Get only rejected responses
$rejected = $res->getRejected();

// Get responses count
$responsesCount = $res->getResponsesCount();

// Get fullfilled responses count
$fullfilledCount = $res->getFullfilledCount();

// Get rejected responses count
$rejectedCount = $res->getRejectedCount();

// Get execution time
$executionTime = $res->getExecutionTime();

// Get if pool is failed
$isFailed = $res->isFailed();

// Get errors
$errors = $res->getErrors();
```

### Errors

[](#errors)

To handle errors, you can just use `HttpPool::make()` method and errors will throw exceptions. But if you want to prevent errors, you can use `throwErrors` param.

```
use Kiwilan\HttpPool\HttpPool;

$pool = HttpPool::make($urls, throwErrors: false);
```

All errors can be found in `getErrors()` method, after pool execution.

```
$res = $pool->execute();
$isFailed = $res->isFailed();
$errors = $res->getErrors();
```

### Response

[](#response)

After pool execution, you can get responses with `getResponses()` method. It returns a `Collection` of `HttpPoolResponse`.

Note

The first item of `getResponses` could not be the first request you sent. It depends of the response time of each request. But you can retrieve the original request with `getMetadata()->getRequest()` method, the best way to find parent is to define an ID, that you could retrieve it with `getId()` method.

```
$responses = $res->getResponses();
$first = $responses->first(); // HttpPoolResponse

$first->getId(); // Get original ID
$first->getMetadata(); // Get HttpPoolResponseMetadata
$first->getGuzzle(); // Get original GuzzleHttp\Psr7\Response
$first->getBody(); // Get HttpPoolResponseBody
$first->isSuccess(); // Get if response is success
$first->isBodyAvailable(); // Get if response body exists
```

### Metadata

[](#metadata)

`HttpPoolResponse` has a `HttpPoolResponseMetadata` attribute, it contains some useful data. Here `$first` is a `HttpPoolResponse`.

```
$metadata = $first->getMetadata();

$statusCode = $metadata->getStatusCode(); // 200, 404, 500...
$status = $metadata->getStatus(); // Guzzle pool status: fullfilled, rejected
$reason = $metadata->getReason(); // OK, Not Found, Internal Server Error...
$isSuccess = $metadata->isSuccess(); // 200 isFailed(); // status code is not success
$isJson = $metadata->isJson(); // is a valid JSON
$isXml = $metadata->isXml(); // is a valid XML
$server = $metadata->getServer(); // Server header
$date = $metadata->getDate(); // Date header
$contentType = $metadata->getContentType(); // Content-Type header
$request = $metadata->getRequest(); // Original request
$headers = $metadata->getHeaders(); // Original headers as array
$header = $metadata->getHeader('Content-Type'); // Extract header (safe method)
```

### Body

[](#body)

`HttpPoolResponseBody` is a wrapper of `GuzzleHttp\Psr7\Stream` with some useful methods. Here `$first` is a `HttpPoolResponse`.

```
$body = $first->getBody();

$isExists = $body->isExists(); // Get if body exists
$contents = $body->getContents(); // Get body contents
$json = $body->getJson(); // Get body as JSON
$xml = $body->getXml(); // Get body as XML
$isBinary = $body->isBinary(); // Get if body is binary
$isJson = $body->isJson(); // Get if body is a valid JSON
$isXml = $body->isXml(); // Get if body is a valid XML
$isString = $body->isString(); // Get if body is a string
$toArray = $body->toArray(); // Get body as array
```

### Advanced

[](#advanced)

You can use some advanced options to customize your pool.

Use URL as identifier to replace ID.

```
HttpPool::make($urls)
  ->setUrlAsIdentifier();
```

Enable console output.

```
HttpPool::make($urls)
  ->allowPrintConsole();
```

#### Memory peak

[](#memory-peak)

Handle memory peak is optional, but if you have a lot of requests, you can use `allowMemoryPeak` to avoid memory peak. New memory peak will be set inside `execute()` method.

Memory peak is set to `2G` by default, you can change it with second param.

```
HttpPool::make($urls)
  ->allowMemoryPeak('2G');
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Guzzle](https://docs.guzzlephp.org/en/stable/quickstart.html) for the awesome HTTP client
- [Laravel](https://laravel.com/docs/10.x/http-client) for `Illuminate\Support\Collection`
- [Symfony](https://symfony.com/) for `symfony/console`
- [Spatie](https://github.com/spatie/package-skeleton-php) for the package skeleton
- [Ewilan Rivière](https://github.com/kiwilan)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

[![](https://user-images.githubusercontent.com/48261459/201463225-0a5a084e-df15-4b11-b1d2-40fafd3555cf.svg)](https://github.com/kiwilan)

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance31

Infrequent updates — may be unmaintained

Popularity23

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 91.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~17 days

Recently: every ~52 days

Total

14

Last Release

784d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/58eb34eac9af07c3352e83060e472e1c280838ebe0568692561c00a2cfde9e57?d=identicon)[ewilan-riviere](/maintainers/ewilan-riviere)

---

Top Contributors

[![ewilan-riviere](https://avatars.githubusercontent.com/u/48261459?v=4)](https://github.com/ewilan-riviere "ewilan-riviere (77 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (5 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (2 commits)")

---

Tags

concurrencyguzzlehttpkiwilanphppoolrequestshttpphpconcurrencyGuzzlepoolrequestskiwilan

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/kiwilan-php-http-pool/health.svg)

```
[![Health](https://phpackages.com/badges/kiwilan-php-http-pool/health.svg)](https://phpackages.com/packages/kiwilan-php-http-pool)
```

###  Alternatives

[kevinrob/guzzle-cache-middleware

A HTTP/1.1 Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack. (RFC 7234)

43117.4M104](/packages/kevinrob-guzzle-cache-middleware)[hannesvdvreken/guzzle-debugbar

A Guzzle middleware that logs requests to debugbar's timeline

76410.4k1](/packages/hannesvdvreken-guzzle-debugbar)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
