Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126616 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 qa.php.net (Postfix) with ESMTPS id A71131A00BC for ; Fri, 7 Mar 2025 08:48:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1741337176; bh=MzgP0D7rKsTT13RtOaew1NrZawrhmqw4/hQx2v+sFIg=; h=References:In-Reply-To:From:Date:Subject:To:From; b=XKfusP8vhcwDuA9XUVcJ5AuemFuJmgvOIFGWqRCWzvoiu8VyCC9n1zG/zUhP6RQBY J5XmPQjjcR/a2GCUbTQRN97lPaVqoWc9tdgyBr/YRMmrBl07PSMt/usi38/+LFtrHd OGzr1gxIokg1eaIdy7OuojQI8eu3UrQVdkcG67SRuI///8/07GLwrqnocQnzKHkEBS kwmB5DAG4MAWPNE4v4b8LEVJhtUN9uOkCEfAl2yFqiDzdxhuWlqzJLTrt5gqs0fLos jzvBPEiaFYSwCdBJIaY8TxB0TC1KA0pj9L4b7hR2fYMFaw7jpFIp14pGpQ7muE2sft fl3yjXJ2IBBXQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 4424A180037 for ; Fri, 7 Mar 2025 08:46:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_40,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yb1-f175.google.com (mail-yb1-f175.google.com [209.85.219.175]) (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 ; Fri, 7 Mar 2025 08:46:15 +0000 (UTC) Received: by mail-yb1-f175.google.com with SMTP id 3f1490d57ef6-e4419a47887so1271612276.0 for ; Fri, 07 Mar 2025 00:48:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1741337330; x=1741942130; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=zdZ3Vmaj24a/8d+7CRCdP/xlPNJI//HBSprjd4p7zU0=; b=jxcX4CCPFBPH7mCCk3QNY4vLCcSSngUJkxPK61Ou3PBGTBzs2G+g94NggIo/un+vma UYWA2uAF7Cl7S0N9pnUinTHiNbIK4/TshmZ2o5Nq5SycVPwDIhUYvJRF8rs4ABHZAtEk TsOc4lddGC7NCdCQcm7F4KVqgKQ4TYg3sXJYjoORGGqOS/WO3sBCnNZyFzI4nHJbjT21 cy1qJdX6pRvTL3F4CG2mvSJchusMTEzNXYc+OPLQYPdsIhGqGD+C+AiKcQpijm/xG6za 9RCM68S8pIsT7AJ9uD9SSvter1sGHe5ixCpYyUEZRw63QjbbL1j577QzYJbVLAHGxh5s fuAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741337330; x=1741942130; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=zdZ3Vmaj24a/8d+7CRCdP/xlPNJI//HBSprjd4p7zU0=; b=Y8NdzM9R2z/08zIS0Q5fwSqJg3VDUo/JsC04CT5cVRZgQG8hP0BzTT9S6I5BZjCL3x JlbCwE7WsooIw1dIon8dcWN9nRepnGVQ/7PS+R5U2krsCP9i1C4OsuM3zoENFJ7cVwpm W9VmP3IPrdYqUYNdooxWgE+Gr4l4P9/f/Ihkw198hHsjSlc/nDibXoEP1ULDiHv4oHIm s+J2hiwaP/4l6wkWO8EE2hGXT78/EXXgEXwssoswczUDKwh2Vrr4YGkI7PZEnt2oiPA3 nfN7nxISBoBpeUZoanhgUKlAKkJ9kFgTTVs9lyTyBStv9iJVT1kUqT0jxOxzG+ay95Wf gvWg== X-Gm-Message-State: AOJu0YxZ4ezzUwcqYUY9j6Jt9ZSDONeY75Oi19dc8Khrm3f3Cv2Npz0o 068FTYgmkLDBYOBL6uNO9lW5sl9XUgzOd9ZAW/QNzuR7omSfzOrqTGAa5c0mO6io7k4XmQsdTVj M6hzxa0sRLUm+fUWfJBHhE4GNiVL1VQ== X-Gm-Gg: ASbGnct0XSCm8uR5Pgqw3hWOBB3RXtF1kyBLvvdU5jny0F+SqZiN1MjeBkqx75S7yGz yWBGZgPeClDyKJ/vNzolgGbBADyNDHmrt8YiD540UndySE8xQ/ueFsGHNzCuBYek2XsaKCMEOIK lEpRKlBJ14MYo5/B8IoLnz5FKIqQ== X-Google-Smtp-Source: AGHT+IGH15sIvqnESWHj0sYgJZU2JCTptgkEL93qCmcWUFkYyPWARpp/PeaNSu0luLPKsHarLPaCSvEHFzTszRjPHv4= X-Received: by 2002:a05:6902:3189:b0:e63:4428:3a1b with SMTP id 3f1490d57ef6-e635c18fff3mr2852797276.26.1741337329698; Fri, 07 Mar 2025 00:48:49 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <9964db8c-0ffe-43d5-8246-47fc76b07180@app.fastmail.com> <78a03dd0-fd4a-4f4a-ad8a-37e5704f06fc@app.fastmail.com> <23e162f6-54b0-4564-9d79-7b3bdc3d1ab5@rwec.co.uk> <36cee7e3-2ef8-4f96-a72e-e67a99e5f9bb@rwec.co.uk> <779046a0-7c70-45a9-82c4-7c31c502cec2@rwec.co.uk> In-Reply-To: Date: Fri, 7 Mar 2025 10:48:38 +0200 X-Gm-Features: AQ5f1JqpAMaSHIZrnb9UjaCj0fd-wm86ExutDHa2GK0rhehlVbrvg3KmEYjm2Mw Message-ID: Subject: Fwd: [PHP-DEV] PHP True Async RFC To: php internals Content-Type: multipart/alternative; boundary="000000000000f8915b062fbcb05d" From: edmond.ht@gmail.com (Edmond Dantes) --000000000000f8915b062fbcb05d Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable > > As far as I know, all current SAPIs follow one of two patterns: > It seems that my example, although taken from real life, is more of an anti-pattern. Let's take a real example that is not an anti-pattern. There is a B2B CRM built on services. Services are classes instantiated in memory only once via DI, and all that. We process requests. Requests are executed within a logical *Scope*. The scope depends on the *TOKEN* and reflects the following entities: - *User Profile* - *Company Settings* We have two implementation options: 1. Pass the user profile and company settings to every method. 2. Use some static variable to make the semantics shorter. When the application runs in separate processes, there are no issues. What do we do? 1. Pass the UserProfile object into DI. 2. Pass the CompanySettings object into DI. Everyone is happy. If it=E2=80=99s a *long-running* process, everyone is tw= ice as happy because the already loaded services and resolved DI are reused multiple times for handling requests. Memory copying is reduced, and for fast requests, we get a nice performance boost. This is especially pleasant for users with a good internet connection. However, this model will not work if each request is processed in a separate coroutine. There are two possible solutions: 1. Pass the *"environment objects"* explicitly through function calls (*= I=E2=80=99d like to see developers doing this and staying in a good mood*). 2. Use something else. There is also a *hybrid solution*, where the service method is called through a *central manager*, the environment objects are stored in function parameters but are injected not by the calling code but by the manager, which extracts them from the current context. However, this approach assumes that the service method *cannot* be called directly, so it is not suitable as a *general solution*. This approach will remain relevant *until PHP becomes a fully multitasking language with parallel execution* (*if that ever happens*). However, there is a strong argument against this. In *Go*, you cannot implement an architecture with global contexts without extra effort. But such solutions have a killer feature: *simplicity*. PHP allows you to implement such architectures, which is one of its strengths. By supporting this approach, we *enhance PHP=E2=80=99s ability* to move in = this direction. This is the perspective in which I try to look at *RFC functions *as an additional tool that should fit into *existing practices*. > ```php function get_query_string_param(string $name): ?string {``` The solution you provided is similar to a real one, but I do not recommend using it for the following reasons: 1. Manual memory management. The coroutine completes, but the data remains. Who will clean it up? 2. The need to write additional code to track memory usage. (call defer() or try/finally each time) 3. The programmer might simply forget 4. Async\Context is shared state, but not a global variable. Async\Context is designed to *guarantee memory management*, which is a key aspect for *long-running* applications. It *automatically releases object references* when a coroutine completes. The programmer does not need to write *extra code* with defer() for this. Second point: Why Async\Context, Channel, and Future should not be just external library objects. There is a dilemma between a *"zoo of solutions"* and *"diversity"*. Languages like *Rust, C, and C++* solve problems where diversity is more important, even at the cost of dealing with a fragmented ecosystem. Example: You need a *hash map function* optimized for *relocatable memory blocks*, but such a thing doesn't exist out-of-the-box. The *more diversity, the better*, as you can choose a solution tailored to your unique case. However, *PHP is not designed for such tasks*. If fundamental primitives in PHP exist in *multiple competing libraries*, it becomes a nightmare. - It=E2=80=99s one thing if *standardized primitives* exist, and librari= es provide alternatives on top of a shared contract. - It=E2=80=99s another if *every developer* has to reinvent the wheel fr= om scratch. If such primitives are not included in this or future RFCs, and instead are left to chance, *it's better not to accept the RFC at all*. This is the reason why the current RFC is large. It helps to see the bigger picture. Once the general principles are agreed upon, we can split it into parts (Incremental Design). Such a plan. Ed. --000000000000f8915b062fbcb05d Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable

>
>=C2=A0 As far as I know, all current SAPIs follow one of two patterns:
>

It seems that my example, although taken from real life,= is more of an anti-pattern. Let's take a real example that is not an a= nti-pattern.

There is a B2B CRM built on services. Services are classes instantiated = in memory only once via DI, and all that. We process requests. Requests are= executed within a logical Scope. The scope depends on the= TOKEN and reflects the following entities:

  • User Profile
  • Company Settings

We have two implementation options:

  1. Pass the user profile and company settings to every method.
  2. Use some static variable to make the semantics shorter.

When the application runs in separate processes, there are no issues. Wh= at do we do?

  1. Pass the UserProfile object into DI.
  2. Pass the CompanySettings object into DI.

Everyone is happy. If it=E2=80=99s a long-running proce= ss, everyone is twice as happy because the already loaded services and reso= lved DI are reused multiple times for handling requests. Memory copying is = reduced, and for fast requests, we get a nice performance boost. This is es= pecially pleasant for users with a good internet connection.

However, this model will not work if each request is processed in a sepa= rate coroutine. There are two possible solutions:

  1. Pass the "environment objects" explicitly th= rough function calls (I=E2=80=99d like to see developers doing this and= staying in a good mood).
  2. Use something else.

There is also a hybrid solution, where the service meth= od is called through a central manager, the environment ob= jects are stored in function parameters but are injected not by the calling= code but by the manager, which extracts them from the current context. How= ever, this approach assumes that the service method cannot= be called directly, so it is not suitable as a general solution.

This approach will remain relevant until PHP becomes a fully mul= titasking language with parallel execution (if that ever happe= ns). However, there is a strong argument against this.
In Go, you cannot implement an architecture with global co= ntexts without extra effort. But such solutions have a killer feature: simplicity
. PHP allows you to implement such architectures, wh= ich is one of its strengths.
By supporting this approach, we enhance PHP=E2=80=99s ability to move in this direction.

This is the perspective in which I try to look at RFC functions= =C2=A0as an additional tool that should fit into existing = practices.

> ```php=C2=A0function get_query_string_param(string $name): ?string {```

The solution you provided= is similar to a real one, but I do not recommend using it for the followin= g reasons:

  1. Manual memory management. The coroutine completes, but the data remains= . Who will clean it up?
  2. The need to write additional code to track memory usage. (call defer() = or try/finally each time)
  3. The programmer might simply forget=C2=A0
  4. Async\Context is shared state, but not a global variable.=C2=A0=C2=A0

Async\Context is designed to guarantee memory = management, which is a key aspect for long-running applications. It automatically releases object references when a coroutine completes. The programmer does not need to write extra code with defer() for this.

Second point: Why Async\Context, Channel, and Futur= e should not be just external library objects.

There is a dil= emma between a "zoo of solutions" and &q= uot;diversity". Languages like Rust, C, and C++ solve problems where diversity is more important, even at the cost of d= ealing with a fragmented ecosystem.

Example: You need a hash = map function optimized for relocatable memory blocks, but such a thing doesn't exist out-of-the-box. The more di= versity, the better, as you can choose a solution tailored to your= unique case.

However, PHP is not designed for such tasks. If fundamental primitives in PHP exist in multiple competing= libraries, it becomes a nightmare.

  • It=E2=80=99s one thing if standardized primitives exis= t, and libraries provide alternatives on top of a shared contract.
  • It=E2=80=99s another if every developer has to reinven= t the wheel from scratch.

If such primitives are not included in this or future RFCs, and inst= ead are left to chance, it's better not to accept the RFC at al= l.

This is the reason why the current RFC is large. It helps= to see the bigger picture. Once the general principles are agreed upon, we= can split it into parts (Incremental Design).=C2=A0=C2=A0=C2=A0

Such= a plan.

Ed.

--000000000000f8915b062fbcb05d--