On 07/03/2025 08:48, Edmond Dantes wrote:
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.


This sounds very much like the same scenario, just different data. The key requirement is to partition the data based on the request. Interestingly, like the previous example, the scope is not per-coroutine, but common to all children of a particular coroutine spawned by some SAPI / networking layer - it seems that some way to "label" coroutines/fibers might be useful.


|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.


That is a good point, and a requirement which I didn't think of.

However, the fact that this didn't stand out in the RFC only reinforces my key points:

1) Having so many different features in one RFC makes it harder to discuss their purpose and design than delivering an overall design first, then adding features.

2) The current Async\Context class doesn't have a clear problem statement. Even with "guaranteed memory management" as a requirement, we could have something much simpler.


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*.


The "or future" in that sentence is key. I'm sorry if I haven't made this clear enough, but I am *not* saying that none of these features belong in core; I'm not even saying we need to tag a release without them. What I'm saying is that they *don't belong in the initial design document*, at least not in this level of detail.


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).


For me, the opposite is true: the size of the RFC is completely obscuring the bigger picture, because I "can't see the forest for the trees", as the saying goes.

I think it's great that you've thought about how these different pieces will interact, but a lot of them can just be sketches of future scope, e.g.

> It may be useful to have an Async\Context object which can safely associate arbitrary data with a particular fiber, to use in place of global/static storage. To do this, we need to track the parent-child relationship of fibers, and have internal hooks at the start and end of a fiber's life to allocate and deallocate the storage. An example of what an Async\Context object implementation might look like is [here], but the details can be discussed at a later stage.

The fact that the parent-child relationship is valuable is a really useful thing to know for the overall design. The fact that you don't like using strings as hashmap keys is not.

As someone not well-versed in the terminology and technology of concurrency, I find it really hard to see which parts of the RFC are far-reaching decisions, and which are just bikeshed colours. As a user, I find it really hard to pick out what PHP code I'll actually write to make use of this - or even whether I'm the target audience at all, or whether this is all likely to be hidden by higher-level libraries.


--
Rowan Tommins
[IMSoP]

Reply via email to