# [RFC] IO Hooks and Operations

- Thread: https://externals.io/message/132727
- Original archive: https://news-web.php.net/php.internals/132727
- Started by Jakub Zelenka on 2026-09-30T18:06:22+00:00
- Messages: 6
- RFC: IO Hooks and Operations (Under discussion) — https://externals.io/rfc/io_hooks.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #132727 — Jakub Zelenka — 2026-09-30T18:06:22+00:00

URL: https://externals.io/message/132727#132727

Hi,

I would like to introduce a new IO Hooks and Operations RFC:

https://wiki.php.net/rfc/io_hooks

Please note that it has got some dependencies to just introduced Polling
API Additions RFC and it also has follow up Ring API support that will be
introduced if this get accepted. It's in early stage and there are things
to change but the API is in the state that it can be discussed. There is
also a working proof of concept that integrates all parts and can be found
at https://github.com/php/php-src/pull/23997 .

Kind regards,

Jakub

---

## #132741 — Edmond Dantes — 2026-10-01T08:10:12+00:00

URL: https://externals.io/message/132727#132741 · In reply to: #132727

Hi!

Great work. I think I could try a test integration and see what issues come up.

чт, 1 окт. 2026 г. в 10:52, Jakub Zelenka <bukka@php.net>:
>
> Hi,
>
> I would like to introduce a new IO Hooks and Operations RFC:
>
> https://wiki.php.net/rfc/io_hooks
>
> Please note that it has got some dependencies to just introduced Polling API Additions RFC and it also has follow up Ring API support that will be introduced if this get accepted. It's in early stage and there are things to change but the API is in the state that it can be discussed. There is also a working proof of concept that integrates all parts and can be found at https://github.com/php/php-src/pull/23997 .
>
> Kind regards,
>
> Jakub

---

## #132743 — Jakub Zelenka — 2026-10-01T08:31:45+00:00

URL: https://externals.io/message/132727#132743 · In reply to: #132741

Hi,


> Great work. I think I could try a test integration and see what issues
> come up.
>

That would be great!

Thanks a lot

Jakub

---

## #132751 — Sebastian Bergmann — 2026-10-01T13:51:38+00:00

URL: https://externals.io/message/132727#132751 · In reply to: #132727

Am 30.09.2026 um 20:06 schrieb Jakub Zelenka:
> I would like to introduce a new IO Hooks and Operations RFC:
> 
> https://wiki.php.net/rfc/io_hooks <https://wiki.php.net/rfc/io_hooks>
Thank you for this RFC, too!

If I understand it correctly, then `proc_close()` and `pcntl_waitpid()` as 
WaitPid operations, and pipe reads that suspend instead of block, 
orchestrating several child processes from PHPUnit's main process may 
become a lot more convenient.

Looking forward to the discussion (and to the future where I can depend on 
this in PHPUnit).

Best,
Sebastian
-- 
Sebastian Bergmann                                 https://phpunit.expert

Stay up to date with PHPUnit: https://phpunit.expert/newsletter

---

## #132759 — Ilia — 2026-10-01T16:47:20+00:00

URL: https://externals.io/message/132727#132759 · In reply to: #132727

> I would like to introduce a new IO Hooks and Operations RFC:
>
> https://wiki.php.net/rfc/io_hooks
>
>
Hi Jakub,

My concern is the safety model. With a provider installed every hooked
call becomes a suspension point inside C code written assuming no PHP
runs during IO. The branch guards the stream, curl, Socket,
XMLReader/XMLWriter and three mysqli entry points. With only the Poll
queue I hit or traced:

- DOMDocument::save() to a pipe, FIFO or ftp:// target: loadXML() or
  removeChild() from another Fiber frees the tree mid-serialize
  (valgrind: reads of the doc freed by loadXML; removeChild segfaults).
- `hash_update_stream()`: `hash_final()` from another Fiber NULLs
  hash->context under the read loop (segfault).
- `libxml_set_streams_context()` during a suspended http read frees the
  context the redirect then reuses.
- mysqlnd shared across Fibers: an unbuffered result can be freed under
  fetch_row, a persistent PDO liveness check can free the connection,
  and pdo_mysql has no guard at all.
- With Files, an include suspends inside opcache's compile window, so
  classes declared meanwhile end up in the cached script.

Guarding objects one at a time won't converge, and third-party
extensions never opted in. I'd flip the default: hooked calls run
synchronously unless the call site declares itself suspension safe.

From running the branch:

1. Pipes are not syscall first, so a 10-byte top-level fwrite(STDOUT)
   to a pipe, or `sleep()`, under the RFC's Scheduler throws FiberError.
   The main flow needs a defined rule.
2. Under a provider STDIN/STDOUT get O_NONBLOCK on the shared file
   description; other processes and `system()` children see it, and it
   survives kill -9. Without one, a proc_open child given a socket as
   stdin gets EAGAIN from dd. Neither is in the BC section.
3. An exception unwinding past a registered stream skips remove(), and
   the next socket on that fd number is never re-armed.
4. Two Fibers `flock()`ing one file deadlock the process.
5. A provider declaring DirectData can complete Write/Send as Done
   without doing anything. I'd keep Files/DirectData/DirectAccept out of
   the userland API until the Ring RFC passes.

Could the hooks be split out of the branch into their own PR? At 23k
lines with the Ring and the Poll additions, it's hard to review.


-- 
Ilia Alshanetsky
Technologist, CTO, Entrepreneur
E: ilia@ilia.ws
T: @iliaa
B: http://ilia.ws

---

## #132763 — Jakub Zelenka — 2026-10-01T17:43:55+00:00

URL: https://externals.io/message/132727#132763 · In reply to: #132759

Hi,



> 
>
> > […]
> Hi Jakub,
>
> My concern is the safety model. With a provider installed every hooked
> call becomes a suspension point inside C code written assuming no PHP
> runs during IO. The branch guards the stream, curl, Socket,
> XMLReader/XMLWriter and three mysqli entry points. With only the Poll
> queue I hit or traced:
>
> - DOMDocument::save() to a pipe, FIFO or ftp:// target: loadXML() or
>   removeChild() from another Fiber frees the tree mid-serialize
>   (valgrind: reads of the doc freed by loadXML; removeChild segfaults).
> - `hash_update_stream()`: `hash_final()` from another Fiber NULLs
>   hash->context under the read loop (segfault).
> - `libxml_set_streams_context()` during a suspended http read frees the
>   context the redirect then reuses.
> - mysqlnd shared across Fibers: an unbuffered result can be freed under
>   fetch_row, a persistent PDO liveness check can free the connection,
>   and pdo_mysql has no guard at all.
> - With Files, an include suspends inside opcache's compile window, so
>   classes declared meanwhile end up in the cached script.
>
> Guarding objects one at a time won't converge, and third-party
> extensions never opted in. I'd flip the default: hooked calls run
> synchronously unless the call site declares itself suspension safe.
>
> From running the branch:
>
> 1. Pipes are not syscall first, so a 10-byte top-level fwrite(STDOUT)
>    to a pipe, or `sleep()`, under the RFC's Scheduler throws FiberError.
>    The main flow needs a defined rule.
> 2. Under a provider STDIN/STDOUT get O_NONBLOCK on the shared file
>    description; other processes and `system()` children see it, and it
>    survives kill -9. Without one, a proc_open child given a socket as
>    stdin gets EAGAIN from dd. Neither is in the BC section.
> 3. An exception unwinding past a registered stream skips remove(), and
>    the next socket on that fd number is never re-armed.
> 4. Two Fibers `flock()`ing one file deadlock the process.
> 5. A provider declaring DirectData can complete Write/Send as Done
>    without doing anything. I'd keep Files/DirectData/DirectAccept out of
>    the userland API until the Ring RFC passes.
>
>
Could the hooks be split out of the branch into their own PR? At 23k
> lines with the Ring and the Poll additions, it's hard to review.
>
>
It's actually noted in the PR that it's still PoC and it's not supposed to
be reviewed yet. But thanks for checking anyway as it's useful but don't
expect to be in the ready state. I don't want to split it at this stage as
it would be pain to maintain but I will do so closer to the vote (which for
hooks quite far). I got actually quite a few of those place on my to do
already but there are some new finding so will update it. All of this will
be, of course, sorted out. I don't see this as a design issue as the
freezing is actually quite strict and prevents many issues so we should be
able to make this safe. In the future we might consider relaxing some of
the rules.

For now I'm mainly seeking the API design review and just want to make sure
that things can work out in the current implementation.

Kind regards,

Jakub
