Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130124 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id 50CA51A00BC for ; Sun, 22 Feb 2026 16:16:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1771777003; bh=NsaMuFwlZcIRUQKNF9cGBLEkNrpCd5Ue898Y6iLMxJI=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=fARZgsyvNDBDNXOUd06hRauSDV44RAGC0OeqOkB7Xp0r7iZSKCZrfqY7cAABSUK08 ovJiXH8ZU+NMw1MPXGty1x1q0IjmQVgHfah4teh2zKW98ozTR2iaX9Qr6lyt4XMPhf u3c4AMIGoTXwuR04UFEXUffZOBPs/uqxnw1WDr22DGzTzI6ugx4MQ5M5mOXScMTsRM wRVZ1lXR7RnQQQF1nnfCcM9/mo2IOlelAYt3D0Nf6J+ElaEDOghziVx2VdahEBgkwQ Jnrcj3Qgz3xT0X5CzfIUJRomlT9q5hzlXbP4RPojAonPgOKYXHkjTGSAtYtJX1AFhl PAnZEAbA1rKgA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CD4E1180050 for ; Sun, 22 Feb 2026 16:16:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: * X-Spam-Status: No, score=1.7 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, DMARC_NONE,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-oi1-f172.google.com (mail-oi1-f172.google.com [209.85.167.172]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 22 Feb 2026 16:16:42 +0000 (UTC) Received: by mail-oi1-f172.google.com with SMTP id 5614622812f47-463967f35d7so2266678b6e.1 for ; Sun, 22 Feb 2026 08:16:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1771776997; cv=none; d=google.com; s=arc-20240605; b=Ve34z+qwRnX008+3mkP3p8mtKJ5J+URXU5jjlLrgUkAIk5iKCzHijs2c//TRxDQJ/u aFFscWbSgwYSEYGBDDzOpvrgvizW3GGakt2KKusQJCvKS7288jq+Sg3xV+4i06RKYrda o5G8nGDnLmoeKPt3dgYPuDCWEgQp/0ZTwweDsT7VCq7R2d2k7BFJbIlG9pOUjRJsdUKm dMZxuaf3Qie67Vv+c4dAeMWD2EwbOhPSfnhH5DN2qgtLXeLFEaOlIJZ61UVKSBPQDztO LTyodGaiQNdNgOsZwpBOqd/5JPjEi3893Qvz5trlUSxJkPtQcdEAHOz+7szTrxCWkjY6 bVQQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version; bh=Dp6qMtrmFUgaZ2NcjkPKvx7OLiT4nrVTmVDk9MLQaGY=; fh=xX59M9k2LJe5CkjPpBTRX27Ve3+5hYeaIKPXnbjUkb8=; b=kno0B0JXNCXZclmvuOfh0V69fF/kbqMlXoGJxPg3fgNGJ9GIoEuFAsTN5I/01s3MMr e6T4VVfJbQZrTBHLir5i+dd0UEbfg6/oMzadf8Pzubkj+METpXbLTjTbJK3suenrV5Dp pnU6Rx3RxwVQGItMZ5AErk1wtEI56ZW0a09g6EnLMaBABE2dMJh9IOAVii94SdrZmLIL 40Sd/+h/mZDkgXyzP54v60RVXQA0jxtitvlIMfiCs/E4DpICgQxJ26nQ5Hp1N7mNghgq MKlusC7k/V9XW4moAtQMK3R+d+ju9BRKphx1GjlIIqpeux22S2+kFZKKbZZRzVOT96lZ 7EUg==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771776997; x=1772381797; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Dp6qMtrmFUgaZ2NcjkPKvx7OLiT4nrVTmVDk9MLQaGY=; b=DRpnHxs/PPjSZJB8OWkKaK7jDaNTy9tsfqdeUp+qg4+/0ZRDWIIAcv1AdPveRoBgex fATuPozNKIo8+XtRcOk8Anoyvk4rvcksvkNZPkpk8UGJdOkGLnwMi4ltE2I77zP313P5 zn9kdu5RI3bmcxxuObUlH3A8v2PcUI0aqaAZtnD0nzAb53yR0eFpG0BosDrmQK/cikUd qSD3+rklC61kSKCw30Rv3KP/tIh2grjGw1pj0wN6/4ct/Thz1HLVMzZmbqHj8Po9yu5L a1WCMSH9LqDaq2KdY5cANiFHe37pC0j5C0fXmvmxp9HQlrvE/MtemaByUPgueoCbm+UP Ws5A== X-Gm-Message-State: AOJu0YyKAmCeLsRvuS7bcdSoXwZFraktSTSaZwWaP1/6a7j6HXncxdCS 53W98oQboYzxwgctd8PW9C2b2C/VPqSDo4bsGwG9iM0sKvGuFgVib8Llp/ofm/PHIv4JYN86+ts LgRDcYlfttW2/EV8FDvrs0qd+gXj3p3mxBhU7 X-Gm-Gg: AZuq6aKcV6DAL1NfFOSSJHgvhZdEszXlcsQ9UabqrxDYwagRigf3rOT7raHyYvrTjXa lYMGtDTxGTcvxy26/lkliOd8+2fSI5DjiTFwYV4cqa3Jk+sG/ZpwbtxrJDHBsiDM235LMICHhds IdoKjduhVZu3viWqImyqNcHJf6mQN7avm4cg6hbHfgb+SSSAQqppxE90ffIBrk3rT90yQ3FcrCV Evibv+gDZMnWcS716BMkJqoxw1/pq1ocG0C3sabluaHezVFlYATLOw5CDI5Y3TfmP49F5uATiAt nJzJ3+0= X-Received: by 2002:a05:6808:1b21:b0:450:cdc3:7a0f with SMTP id 5614622812f47-464463f8712mr3472245b6e.57.1771776996619; Sun, 22 Feb 2026 08:16:36 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <926a26a6-eb89-49aa-a387-6cc79caa29c1@bastelstu.be> In-Reply-To: <926a26a6-eb89-49aa-a387-6cc79caa29c1@bastelstu.be> Date: Sun, 22 Feb 2026 17:16:25 +0100 X-Gm-Features: AaiRm53C2NyWhIo_ip-r5MX_TV8uLJa1ijPrzsCtqSPncKdc2-GxCe2kol3f2N8 Message-ID: Subject: Re: [PHP-DEV] [RFC] Polling API To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= Cc: PHP internals list Content-Type: multipart/alternative; boundary="000000000000813b5d064b6bfac4" From: bukka@php.net (Jakub Zelenka) --000000000000813b5d064b6bfac4 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi, Thanks for the feedback! On Sun, Jan 18, 2026 at 1:24=E2=80=AFPM Tim D=C3=BCsterhus wrote: > Hi > > On 10/30/25 22:06, Jakub Zelenka wrote: > > I would like to introduce a new polling API RFC that is part of my stre= am > > evolution work: > > > > https://wiki.php.net/rfc/poll_api > > Since you made some larger changes to the RFC, rather than checking each > change individually, I've taken another full look at the RFC and have > the following remarks: > > - Context::wait() takes a millisecond timeout. This feels insufficiently > granular. I am wondering if we should rather use either micro (as > returned by microtime) or nanoseconds (as returned by hrtime) - or > possible an instance of DateInterval (which would use microsecond > resolution). > Yeah this makes sense. I used the same convention that is used in streams which means two params so it is changed to: public function wait(int $timeoutSeconds =3D -1, int $timeoutMicroseconds = =3D 0, int $maxEvents =3D -1): array {} > - For Handle: I assume that getFileDescriptor() should be abstract? > I actually thought that it might be nicer to have default method for internal classes but that wouldn't work well for user classes anyway so it's better to make it abstract which I just did. > - For Handle I am wondering about abstract class vs interface. Since the > Handle presumably doesn't have any non-abstract methods, an interface > feels more correct / more flexible. > I have been considering this already and there are reasons why I prefer abstract method here. The abstract method is better for internal implementation and limit overhead of PHP calls that would be required for interface. The advantage is that I can use internal struct API through C operations which allows bypasing the call and can do optimization for some backends - e.g. timeouts for kqueue don't need file descriptor. I also think that there is not really much use case for user space to implement their own handles so such interface would be used only internally anyway. In addition interface would effectively expose the internal stream fd which is currently hidden and makes harder messing up with stream fd which might cause various issues. > - For Handle: What happens if I extend this class in userland and attach > it to a Context. Will things break? What if I return the number of a > non-existent FD? > Depending on backend it will result either in FailedHandleAddException (epoll, kqueue, possible event ports as well) or on Windows it would likely fail during wait with FailedPollWaitException. So it can be handled by catching FailedPollOperationException. This is however very unlikely edge case so I don't think there is much point to worry about consistency. As I said the use case for implementing custom Handle is a bit moot. > - For the stubs: It would be useful if you used the =E2=80=9Cgenerics not= ation=E2=80=9D > for the array returns. e.g. `@return list` for > Backend::getAvailableBackends(). This makes it easier to understand how > exactly the result will look like to check for mistakes / suboptimal > choices. > Makes sense. I added it also for Watcher::getTriggeredEvents, Watcher::getWatchedEvents that return list and Context::wait that returns list. > - InactiveWatcherException: This one feels more like a programmer error, > so should possibly be a PollError / InactiveWatcherError (but I don't > know enough about the topic to be sure). > I don't think it should be error as it is not necessary for user to track removal of watcher (which can also happen automatically for one shot events). It should be just fine to normally recover from this rather than requiring checking for isActive. It's more state issue which is usually handled using exceptions IMHO. > - Internal API: For php_poll_wait(), the timeout should probably be a > struct timespec for future-proofing. > > This has been changed as suggested (together with introducing microseconds support for user space). In addition to the above changes I also changed ValueError for passing backend that is not available on the current platform to new BackendUnavailableException as this is more runtime specific issue that application might want to handle rather than forcing users to always use Backend::isAvailable. Basically I feel if something can vary and it's not possible to be immediately caught by developer (because they can develop it on different platform), then it should be more an exception than error. Kind regards, Jakub --000000000000813b5d064b6bfac4 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi,

Thanks for the feedback!

On Sun, Jan 18, 2= 026 at 1:24=E2=80=AFPM Tim D=C3=BCsterhus <tim@bastelstu.be> wrote:
Hi

On 10/30/25 22:06, Jakub Zelenka wrote:
> I would like to introduce a new polling API RFC that is part of my str= eam
> evolution work:
>
> https://wiki.php.net/rfc/poll_api

Since you made some larger changes to the RFC, rather than checking each change individually, I've taken another full look at the RFC and have <= br> the following remarks:

- Context::wait() takes a millisecond timeout. This feels insufficiently granular. I am wondering if we should rather use either micro (as
returned by microtime) or nanoseconds (as returned by hrtime) - or
possible an instance of DateInterval (which would use microsecond
resolution).

Yeah this makes sense. I u= sed the same convention that is used in streams which means two params so i= t is changed to:

public function wait(int $timeoutSeconds =3D -1, in= t $timeoutMicroseconds =3D 0, int $maxEvents =3D -1): array {}
= =C2=A0
- For Handle: I assume that getFileDescriptor() should be abstract?

I actually thought that it might be nicer to h= ave default method for internal classes but that wouldn't work well for= user classes anyway so it's better to make it abstract which I just di= d.
=C2=A0
- For Handle I am wondering about abstract class vs interface. Since the Handle presumably doesn't have any non-abstract methods, an interface <= br> feels more correct / more flexible.

I h= ave been considering this already and there are reasons why I prefer abstra= ct method here.

The abstract method is better for = internal implementation and limit overhead of PHP calls that would be requi= red for interface. The advantage is that I can use internal struct API thro= ugh C operations which allows bypasing the call and can do optimization for= some backends - e.g. timeouts for kqueue don't need file descriptor.

I also think that there is not really much use case= for user space to implement their own handles so such interface would be u= sed only internally anyway.

In addition interface = would effectively expose the internal stream fd which is currently hidden a= nd makes harder messing up with stream fd which might cause various issues.=

=C2=A0
- For Handle: What happens if I extend this class in userland and attach it to a Context. Will things break? What if I return the number of a
non-existent FD?

Depending on backend i= t will result either in=C2=A0FailedHandleAddException (epoll, kqueue, possi= ble event ports as well) or on Windows it would likely fail during wait wit= h=C2=A0FailedPollWaitException. So it can be handled by catching FailedPoll= OperationException. This is however very unlikely edge case so I don't = think there is much point to worry about consistency. As I said the use cas= e for implementing custom Handle is a bit moot.=C2=A0
=C2=A0
- For the stubs: It would be useful if you used the =E2=80=9Cgenerics notat= ion=E2=80=9D
for the array returns. e.g. `@return list<Backend>` for
Backend::getAvailableBackends(). This makes it easier to understand how exactly the result will look like to check for mistakes / suboptimal
choices.

Makes sense. I added it also f= or Watcher::getTriggeredEvents, Watcher::getWatchedEvents that return list&= lt;Event> and Context::wait that returns list<Watcher>.
= =C2=A0
- InactiveWatcherException: This one feels more like a programmer error, so should possibly be a PollError / InactiveWatcherError (but I don't <= br> know enough about the topic to be sure).

I=C2=A0 don't think it should be error as it is not necessary for use= r to track removal of watcher (which can also happen automatically for one = shot events). It should be just fine to normally recover from this rather t= han requiring checking for isActive. It's more state issue which is usu= ally handled using exceptions IMHO.
=C2=A0
- Internal API: For php_poll_wait(), the timeout should probably be a
struct timespec for future-proofing.


This has been changed as suggested (together with introducing microsecond= s support for user space).

In addition to the abov= e changes I also changed ValueError for passing backend that is not availab= le on the current platform to new BackendUnavailableException as this is mo= re runtime specific issue that application might want to handle rather than= forcing users to always use Backend::isAvailable. Basically I feel if some= thing can vary and it's not possible to be immediately caught by develo= per (because they can develop it on different platform), then it should be = more an exception than error.

Kind regards,
<= div>
Jakub
--000000000000813b5d064b6bfac4--