pfinalclub/asyncio-http-core

๐Ÿš€ Production-grade async HTTP client for pfinal-asyncio ecosystem | ็”Ÿไบง็บงๅผ‚ๆญฅ HTTP ๅฎขๆˆท็ซฏ

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/pfinalclub/asyncio-http-core

1.0.0 2025-11-25 09:01 UTC

This package is auto-updated.

Last update: 2025-11-25 09:10:58 UTC


README

๐Ÿš€ Production-Grade Async HTTP Client for PHP

License PHP Version Asyncio Version PSR-7 PSR-18

English | ไธญๆ–‡ๆ–‡ๆกฃ

Part of the pfinal-asyncio ecosystem

๐Ÿ“– Overview

AsyncIO HTTP Core is a production-grade, high-performance async HTTP client built on top of the pfinal-asyncio framework. It leverages PHP 8.1+ Fiber technology to provide true asynchronous I/O with a clean, synchronous-looking API.

๐ŸŽฏ Key Features

  • ๐Ÿš€ True Async I/O - Native PHP 8.1+ Fiber, zero blocking
  • โšก Zero-Config Concurrency - Built-in gather() and Semaphore support
  • ๐Ÿ“ฆ PSR Standards - Full PSR-7 (HTTP Message) & PSR-18 (HTTP Client) compliance
  • ๐Ÿ”ง Middleware System - Flexible onion-model middleware architecture
  • ๐ŸŽจ Elegant API - Intuitive, requests-like interface
  • ๐Ÿ”„ Connection Reuse - Automatic HTTP Keep-Alive with connection pooling
  • ๐Ÿ›ก๏ธ Production Ready - Battle-tested error handling and retry policies
  • ๐Ÿ“Š Monitoring - Built-in metrics and performance tracking
  • ๐ŸŒ HTTP/1.1 & HTTP/2 - Protocol version negotiation support

๐Ÿ“‹ Requirements

Requirement Version Notes
PHP >= 8.1 Fiber support required
pfinalclub/asyncio ^3.0 Core async runtime
Workerman >= 4.1 Event loop (auto-installed)
ext-ev (optional) * 10-20x performance boost ๐Ÿš€
ext-event (optional) * 3-5x performance boost โšก

๐Ÿ“ฆ Installation

composer require pfinalclub/asyncio-http-core

๐Ÿ”ฅ Performance Boost (Recommended)

For production environments, install the ev extension for maximum performance:

# macOS
brew install libev
pecl install ev

# Ubuntu/Debian
sudo apt-get install libev-dev
pecl install ev

# CentOS/RHEL
sudo yum install libev-devel
pecl install ev

Performance Comparison:

Event Loop Throughput Speed
Select (default) 80 req/s 1x baseline
Event 322 req/s 4x faster โšก
Ev 833 req/s 10.4x faster ๐Ÿš€

๐Ÿš€ Quick Start

Basic Request

<?php
require 'vendor/autoload.php';

use PFinal\AsyncioHttp\Client;
use function PfinalClub\Asyncio\run;

run(function() {
$client = new Client();

    // Simple GET request
    $response = $client->get('https://api.github.com/users/octocat');
echo $response->getBody();

    // POST with JSON
$response = $client->post('https://api.example.com/users', [
        'json' => ['name' => 'Alice', 'email' => 'alice@example.com']
]);
    
    echo "Status: {$response->getStatusCode()}\n";
});

Concurrent Requests

use function PfinalClub\Asyncio\{run, create_task, gather};

run(function() {
    $client = new Client();
    
    // Create concurrent tasks
    $tasks = [
        create_task(fn() => $client->get('https://api.github.com/users/octocat')),
        create_task(fn() => $client->get('https://api.github.com/users/torvalds')),
        create_task(fn() => $client->get('https://api.github.com/users/gvanrossum')),
    ];
    
    // Execute concurrently and wait for all
    $responses = gather(...$tasks);
    
    foreach ($responses as $i => $response) {
        echo "User {$i}: {$response->getStatusCode()}\n";
    }
});

Batch Requests with Pool

use PFinal\AsyncioHttp\Pool;

run(function() {
    $client = new Client();
    
    // Create 100 requests
    $requests = [];
        for ($i = 1; $i <= 100; $i++) {
        $requests[] = fn() => $client->get("https://api.example.com/items/{$i}");
    }
    
    // Execute with concurrency limit of 25
    $results = Pool::batch($client, $requests, [
        'concurrency' => 25,
        'fulfilled' => fn($response, $index) => echo "โœ… Request {$index} succeeded\n",
        'rejected' => fn($e, $index) => echo "โŒ Request {$index} failed: {$e->getMessage()}\n",
    ]);
    
    $successCount = count(array_filter($results, fn($r) => $r['state'] === 'fulfilled'));
    echo "Success: {$successCount}/100\n";
});

๐Ÿ’ก Why No Async Methods?

Unlike traditional Promise-based async libraries, pfinalclub/asyncio uses PHP Fiber. In Fiber, operations look synchronous but execute asynchronously.

// โŒ Traditional async libraries (Guzzle, ReactPHP)
$promise = $client->getAsync('https://api.example.com');
$response = $promise->wait();  // Explicit wait

// โœ… pfinalclub/asyncio (Fiber-based)
$response = $client->get('https://api.example.com');  // Auto-async!

The magic: When called inside run() or a Fiber, operations automatically yield control to the event loop, enabling true concurrency without callbacks or explicit promises.

๐Ÿ”ง Advanced Usage

Middleware System

use PFinal\AsyncioHttp\Handler\{HandlerStack, AsyncioHandler};
use PFinal\AsyncioHttp\Middleware\{RetryMiddleware, RedirectMiddleware, LogMiddleware};

run(function() {
    $handler = new AsyncioHandler();
    $stack = HandlerStack::create($handler);
    
    // Add retry middleware with exponential backoff
    $stack->push(new RetryMiddleware([
        'max' => 3,
        'delay' => RetryMiddleware::exponentialBackoff(500, 5000),
        'on_retry' => fn($attempt) => echo "Retry attempt {$attempt}\n",
    ]), 'retry');
    
    // Add redirect middleware
    $stack->push(new RedirectMiddleware(['max' => 5]), 'redirect');
    
    // Add logging middleware
    $stack->push(new LogMiddleware($logger), 'log');
    
    $client = new Client(['handler' => $stack]);
    
    // Requests automatically retry, redirect, and log
    $response = $client->get('https://api.example.com/data');
});

Built-in Middleware

Middleware Description
RetryMiddleware Automatic retry with exponential backoff
RedirectMiddleware HTTP redirect handling (301, 302, etc.)
AuthMiddleware Basic/Bearer authentication
CookieMiddleware Cookie jar management
LogMiddleware Request/response logging
HistoryMiddleware Request history tracking
HttpErrorsMiddleware Convert HTTP errors to exceptions
ProgressMiddleware Upload/download progress tracking

Request Options

$response = $client->request('POST', 'https://api.example.com/data', [
    // Query parameters
    'query' => ['page' => 1, 'limit' => 20],
    
    // Headers
    'headers' => [
        'User-Agent' => 'MyApp/1.0',
        'Accept' => 'application/json',
    ],
    
    // JSON body
    'json' => ['name' => 'Bob', 'age' => 30],
    
    // Form data
    'form_params' => ['username' => 'bob', 'password' => 'secret'],
    
    // Raw body
    'body' => 'raw data',
    
    // Timeout (seconds)
    'timeout' => 10,
    
    // SSL verification
    'verify' => true,
    
    // Retry configuration
    'retry' => [
        'max' => 3,
        'delay' => 1000,  // milliseconds
    ],
    
    // Redirect configuration
    'allow_redirects' => [
        'max' => 5,
        'strict' => false,
    ],
    
    // Proxy
    'proxy' => [
        'http' => 'tcp://proxy.example.com:8080',
        'https' => 'tcp://proxy.example.com:8080',
    ],
]);

๐ŸŽฏ Real-World Examples

Building an API Client

class GitHubClient
{
    private Client $client;
    
    public function __construct(string $token)
    {
        $this->client = new Client([
            'base_uri' => 'https://api.github.com',
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'Accept' => 'application/vnd.github.v3+json',
            ],
            'timeout' => 10,
        ]);
    }
    
    public function getUser(string $username): array
    {
        $response = $this->client->get("/users/{$username}");
        return json_decode($response->getBody(), true);
    }
    
    public function getReposConcurrently(string $username, int $pages = 3): array
    {
        // Fetch multiple pages concurrently
        $tasks = [];
        for ($page = 1; $page <= $pages; $page++) {
            $tasks[] = create_task(fn() => $this->client->get("/users/{$username}/repos", [
                'query' => ['page' => $page, 'per_page' => 100]
            ]));
        }
        
        $responses = gather(...$tasks);
        
        $repos = [];
        foreach ($responses as $response) {
            $repos = array_merge($repos, json_decode($response->getBody(), true));
        }
        
        return $repos;
    }
}

// Usage
run(function() {
    $github = new GitHubClient('your-token-here');
    
    $user = $github->getUser('octocat');
    echo "User: {$user['name']}\n";
    
    $repos = $github->getReposConcurrently('octocat', 3);
    echo "Total repos: " . count($repos) . "\n";
});

Web Scraping

run(function() {
    $client = new Client(['timeout' => 10]);
    
    // Fetch homepage
    $response = $client->get('https://news.ycombinator.com');
    preg_match_all('/<a href="(item\?id=\d+)">/', $response->getBody(), $matches);
    $links = array_slice($matches[1], 0, 30);
    
    // Scrape all links concurrently (10 concurrent requests)
    $tasks = array_map(
        fn($link) => fn() => $client->get("https://news.ycombinator.com/{$link}"),
        $links
    );
    
    $results = Pool::batch($client, $tasks, [
        'concurrency' => 10,
        'fulfilled' => fn($response, $i) => echo "โœ… Scraped: {$links[$i]}\n",
        'rejected' => fn($e, $i) => echo "โŒ Failed: {$links[$i]}\n",
    ]);
    
    echo "Scraped: " . count($results) . " pages\n";
});

๐Ÿ” Comparison with Other Libraries

Feature AsyncIO HTTP Guzzle ReactPHP Amphp
Base Technology PHP Fiber cURL Event Loop Event Loop
Async Model Native Coroutine Sync/Promise Promise/Callback Promise/Generator
Code Style Sync-looking (actually async) Synchronous Callback-heavy Generator-based
Performance โญโญโญโญโญ โญโญโญ โญโญโญโญ โญโญโญโญ
Learning Curve Easy ๐Ÿ“š Easy ๐Ÿ“š Steep ๐Ÿ“š๐Ÿ“š๐Ÿ“š Moderate ๐Ÿ“š๐Ÿ“š
Concurrency Control Built-in Manual Complex Built-in
PSR Standards โœ… PSR-7/18 โœ… PSR-7/18 โŒ โœ… PSR-7
Middleware โœ… Onion Model โœ… Onion Model Manual Manual

๐Ÿ“š Documentation

Core Documentation

Examples

Explore the examples/ directory for complete working examples:

  • 01_basic_request.php - Basic HTTP requests
  • 02_concurrent_requests.php - Concurrent request patterns
  • 03_pool_example.php - Pool batch processing
  • 04_middleware_auth.php - Authentication middleware
  • 05_retry_middleware.php - Retry strategies

Ecosystem Packages

Part of the pfinal-asyncio ecosystem:

๐Ÿงช Testing

# Run all tests
composer test

# Run specific test suites
composer test:unit
composer test:integration

# Generate coverage report
composer test:coverage

# Run static analysis
composer phpstan
composer psalm
composer analyse

# Fix code style
composer cs-fix

# Run complete QA suite
composer qa

๐Ÿ“Š Performance Benchmarks

Run benchmarks to see performance metrics:

composer benchmark

Example results (100 concurrent requests):

Event Loop    | Time (s) | Throughput | Speed
--------------+----------+------------+-------
Select        |   1.25   |  80 req/s  | 1x
Event         |   0.31   | 322 req/s  | 4x โšก
Ev            |   0.12   | 833 req/s  | 10.4x ๐Ÿš€

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide for details.

Development Setup

git clone https://github.com/pfinalclub/asyncio-http-core.git
cd asyncio-http-core
composer install
composer test

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

๐Ÿ“ž Support

๐ŸŒŸ Star History

If you find this project useful, please consider giving it a star! โญ

Version: 1.0.0
Release Date: 2025-01-24
Status: Stable Release

๐Ÿš€ Production-Grade Async HTTP Client for PHP!

Built with โค๏ธ by the pfinal-asyncio team