Search by

byjg / phpthread

byjg

ByJG PHPThread simplifies working with threads and non-blocking code in PHP, bridging the gap for a language that was not inherently designed for threading.

Package info

github.com/byjg/php-phpthread

pkg:composer/byjg/phpthread

Statistics

Installs: 26 951

Dependents: 0

Suggesters: 0

Stars: 7

Open Issues: 1

6.0.0 2025-11-25 14:28 UTC

This package is auto-updated.

Last update: 2026-10-20 19:21:36 UTC


README

sidebar_key phpthread
tags
php concurrency

ByJG PHPThread: Simplified Threads and Non-Blocking Code in PHP

ByJG PHPThread simplifies working with threads and non-blocking code in PHP, bridging the gap for a language that was not inherently designed for threading.

Sponsor Build Status Opensource ByJG Install MCP Server GitHub source GitHub license GitHub release

Table of Contents

  1. Overview
  2. Why Threads in PHP?
  3. How It Works
  4. Features
  5. Limitations
  6. Installation
  7. Running Tests

Overview

PHPThread is a polyfill library that abstracts threading functionality for PHP, providing a consistent interface regardless of the underlying PHP setup (ZTS or Fork). It empowers developers to implement thread-like behavior and asynchronous processing in PHP applications.

Why Threads in PHP?

PHP is traditionally designed for a request-response cycle, where scripts are executed only in response to client requests and terminate after sending a response. While efficient for web applications, this architecture lacks native threading support for background or concurrent tasks.

With PHPThread, you can overcome these limitations by leveraging:

  • Forking (Default PHP) for simulating threading.
  • Zend Thread Safety (ZTS) for true multi-threading environments.
  • Child PHP processes (proc_open) outside the CLI, e.g. under PHP-FPM.

How It Works

Default PHP (Non-ZTS)

In standard PHP installations (without ZTS), threading is simulated using the fork command. This approach creates a new process by cloning the parent process. While not a true thread, this method can approximate threading behavior.

Requirements:

  • pcntl and posix: For process control. They are optional (suggest in composer.json): without them the ProcessHandler is used.
  • A tmpfs mounted at /dev/shm: For sharing results between processes.

PHP ZTS (Zend Thread Safety)

With ZTS-enabled PHP, true multi-threading becomes possible. This setup is ideal for production environments where robust threading is required. The ZTS version is compiled with the --enable-zts flag, but it may not be included in all PHP distributions.

Requirements:

  • parallel: For multi-threading functionality.

Outside the CLI

Forking and parallel only work in the CLI. Outside it, the ProcessHandler runs each closure in a child PHP CLI process started with proc_open() (the approach of amphp/parallel). The closure is serialized with laravel/serializable-closure, so it, its arguments and its result must be serializable (no resources). See ProcessHandler.

Requirements:

  • proc_open() enabled and a PHP CLI binary (found automatically, or set with ProcessHandler::setPhpBinary()).
  • A tmpfs mounted at /dev/shm: used by promises.

Features

  • Thread Management: Simplified thread creation and execution (docs).
  • Thread Pools: Efficiently manage and reuse threads for multiple tasks (docs).
  • Promises: Truly asynchronous and non-blocking task management with a JavaScript-like Promise API (docs, benchmark).

Supported Promise Methods:

  • then(): Execute a callback on promise resolution (and, optionally, on rejection).
  • catch(): Execute a callback on promise rejection; the returned promise resolves with its return value.
  • finally(): Execute a callback after resolution or rejection; the original value or reason is passed through.
  • Promise::resolve(): Resolve a promise.
  • Promise::reject(): Reject a promise.
  • Promise::all(): Wait for all promises to resolve.
  • Promise::race(): Wait for the first promise to resolve.

Limitations

See also Limitations.

Parallel Execution Outside the CLI

:::caution Important In web server environments such as PHP-FPM, Apache with mod_php or FrankenPHP, pcntl_fork() and parallel cannot be used. There Thread::create() returns a ProcessHandler: the closure runs in parallel in a child PHP CLI process, so it must be serializable (see ProcessHandler for the limits).

When proc_open() is disabled or no PHP CLI binary is found, it falls back to the SyncHandler: the closure runs synchronously in the current process when start() is called. The code keeps working (threads, thread pools and promises return the same results), but there is no parallelism: the work is done one task after another. :::

To know which handler is used, call Thread::handlerClass() (the class Thread::create() returns in the current environment) or getClassName() on the created thread:

use ByJG\PHPThread\Handler\SyncHandler;
use ByJG\PHPThread\Thread;

if (Thread::handlerClass() === SyncHandler::class) {
    // No parallelism here: ParallelHandler, ForkHandler or ProcessHandler are not available
}

Thread::useHandler(SyncHandler::class) forces the synchronous execution (e.g. in tests, or for a deterministic run), and Thread::useHandler(null) restores the automatic choice.

Why?

  • pcntl extension (used for forking): forking a web server worker would interfere with the server's own process management, so the library only forks in the CLI.
  • parallel extension (used for true threading): requires a ZTS build and the CLI.
  • proc_open (used by the ProcessHandler) starts a separate PHP CLI process, which is safe in any SAPI, at the cost of starting PHP (and the Composer autoloader) for each thread.

Use Cases:

This library is designed for:

  • CLI scripts and daemons
  • Background job processors
  • Command-line tools
  • Long-running CLI applications
  • Scheduled tasks (cron jobs)
  • Running a few independent tasks in parallel inside a web request

For long or many background tasks in web applications, consider using message queues (RabbitMQ, Redis, etc.) with background workers running in CLI mode.

Forking and Data Sharing

When simulating threads with fork, data cannot be returned directly from the child process to the parent. The library serializes the results to the tmpfs filesystem (/dev/shm) to share them between processes.

However:

  • Avoid returning large or complex objects, as this may cause memory exhaustion.

Installation

Requirements

Non-ZTS (Default PHP)

  • PHP ≥8.3
  • pcntl and posix extensions (optional: without them the ProcessHandler runs the threads)
  • tmpfs mounted at /dev/shm

Outside the CLI (PHP-FPM, ...)

  • PHP ≥8.3
  • proc_open() enabled and a PHP CLI binary installed next to the server one
  • tmpfs mounted at /dev/shm (for promises)

ZTS (Zend Thread Safety)

  • PHP ≥8.3 compiled with --enable-zts
  • parallel extension
  • pcntl and posix extensions (optional)

Install via Composer

composer require byjg/phpthread

Running Tests

docker compose up -d
vendor/bin/phpunit

Open source ByJG