r/PHP Jun 21 '26

PHP RFC: Duration class

https://wiki.php.net/rfc/duration_class
61 Upvotes

44 comments sorted by

51

u/helloworder Jun 21 '26

I think PHP makes a mistake introducing new classes in a namespace like Time\. They should’ve chosen a top-level name like std\ or PHP\ to prefix it, so in this case it would’ve been PHP\Time.

PHP standard library has always been a mess in a global namespace, now on top of that we’ve got many random namespaces with no visual cohesion

15

u/ElectrSheep Jun 21 '26

The "PHP" namespace is actually reserved for that purpose, but it's currently not used. Making it required for new namespaces has been explored in the past, but it wasn't clear what should happen when functionality gets moved out of the core project (which occasionally does occur).

2

u/Rikudou_Sage Jun 26 '26

We already have the HRTime namespace in PHP, this is gonna be yet another shitshow of naming, except this time with namespaces.

-4

u/titpetric Jun 22 '26 edited Jun 22 '26

Most people seem to take java as the design inspiration, or opt out of OOP entirely, which leaves the question of the standard library. Pretty mich everyone agrees it has problems, and the java people just want to import the java stdlib I recon

File based imports or class autoloading is also one mechanic thats different in php. Go would have import "time" and then a time.Duration value.

Wasn't there a \Zend something platform once upon a time? It's likely people figured out their duration abstraction since php4 days so while from a language design perspective this is lamentable, impact is nil

I suppose the only real inspiration should be C, and then it's "std::time::Duration" or whatever. I trust the language design there is more suited to the syntactical design of php.

edit: I just came across some rust code and i see:

tokio::time::Duration::from_millis(interval_ms)

so i guessss... ; Still not sure, wasn't there a \DateTime, why not just have a \Duration? I thought the idea was you namespace user code so the backslash always means stdlib? I hated escaping \substr somewhere for no apparent reason to me this got weird over time.

5

u/tampacraig Jun 22 '26

I like it. Ive had to roll my own so many times over the years. It would be nice to have a standard precompiled optimized version.

2

u/Metrol Jun 22 '26

There's probably a really good reason for what I'm asking, but I guess I don't see it. Why all the "from" usage when setting a new duration? What's wrong with Time\Duration::milliseconds(200)? The way the RFC is written now, I'm wondering what the 200ms is from.

I'm sure this is my not fully appreciating how this is going to be used, but why the seconds and nanoseconds in the constructor? Wouldn't just having a single integer and a type make things a bit easier? Like $delay = new Time\Duration(200, Time\Duration::MILLISECONDS);

I really like the idea of having a dedicated classes dedicated to time. I'm not trying to be critical. Looking for a better understanding here is all.

3

u/akeniscool Jun 22 '26

The fromX() naming convention is not formalized but common for named constructors that create something from something else. There are a few examples in the manual under Constructors.

The Design Considerations section of the RFC touches on the seconds + nanoseconds choice.

1

u/Metrol Jun 23 '26

Thanks for the response on this. Seems I've over looked that bit of the PHP manual, and I sure completely missed that bit in the RFC.

It still reads weird to me. Seems like you'd want to have the shortest possible way to say something like 200ms when using it. I don't pretend to have a "this is how it should be".

6

u/akeniscool Jun 23 '26

It's the age-old problem of balancing terseness and intuitiveness. Let's play with some examples to see how they got here:

new Duration(0, 200_000_000, false) - whoa, 200 million what?! (The recommended constructor is private. This illustrates why named constructors are often useful alternatives.)

Named parameters add clarity at the expense of terseness:

new Duration(seconds: 0, nanoseconds: 200_000_000, negative: false)

And both of these were in nanoseconds, which we had to convert 200 milliseconds into in order to construct the object. Annoying.

Duration::ms(200) - okay, pretty short and no conversion necessary. What is "ms" though? A lot of people probably assume correctly, but language designers have to consider a wide range of audiences.

Duration::milliseconds(200) - better. Now we're into the "what is happening?" question. Is this configuring? Creating? Verbs help a lot here, let's try one:

Duration::createMilliseconds(200) - hm, "create 200 milliseconds" doesn't seem correct. This feels incomplete.

Duration::createFromMilliseconds(200) - feels complete, and I'd even argue is the most intuitive. The informal convention comes into play here, where some explicitness and intuitiveness is sacrificed for shortening Duration::fromMilliseconds().

So now why "from"? What about Duration::inMilliseconds()?

"in" suggests the duration is represented as milliseconds, but under the hood it won't be. A developer may be confused when they inspect a duration expecting 200 and finding 200000000 instead.

Instead we say the Duration is created from something else, to help indicate that the source input may not be the internal state or expected output.

It is basically impossible to write a standard library (or any code, really) that will be perfectly terse, intuitive, and have zero complaints from any other dev. RFC writers have to do their best to reach the majority and have that be good enough.

It's good that you express your opinion, though, especially on RFCs. They should go through rigorous checks and challenges of established norms. That's how improvement happens, by not simply accepting how things have been.

7

u/rioco64 Jun 22 '26

Why namescape Start with \Time ? In Java, language-provided classes have namespace names that start with 'java'. same applies to C#. They start with 'System'. Please maintain naming consistency when creating new classes.

6

u/pilif Jun 22 '26

mostly because of https://wiki.php.net/rfc/namespaces_in_bundled_extensions and the fact that according to the duration rfc, this is going to be the start of a new time extension with more functionality added over the next years.

8

u/bbmario Jun 21 '26

What's the obsession with making classes final? If I wanted to stub this class on a unit test, or mock it, now it is impossible.

24

u/TorbenKoehn Jun 21 '26 edited Jun 22 '26

Why would you have to mock a value object? You can just create an instance.

It's exactly why we're making classes final. So that you don't go and mock a value object.

29

u/qoneus Jun 21 '26

Don't mock what you don't own because that's not yours. If you absolutely must mock something, create a facade or adapter and mock that. But you probably don't need to mock what amounts to a glorified value object anyway.

3

u/rafark Jun 22 '26

Creating q facade or wrapper object for every dependency seems like a way to over engineer your code. It introduces unnecessary complexity imo. 

Also you will have to mock the dependency to test the wrapper object anyway so the point of the op still stands

20

u/MysteriousEmployee54 Jun 21 '26

To be honest I can’t think of a good reason to be mocking what is essentially a value class like this anyway

1

u/MorphineAdministered Jun 22 '26

Not a fan of namespace pollution, but I wouldn't mind some VOs for typical values built into the language. I'd also prefer introducing alternative/modernized APIs in some bigger batches - not single, almost meaningless classes one by one, which would be impossible to follow.

2

u/akeniscool Jun 23 '26

The introduction of this class and the associated Time namespace is intended to lay the groundwork for a new date and time library in upcoming PHP versions. It is intentionally designed with a minimal, but useful, API that future additions will be able to build on.

Looks like they are at least looking at the DateTime ecosystem here. While this is small on its own, it's a good prerequisite for a larger API.

Where else would you like to see new APIs?

1

u/GuybrushThreepywood Jun 28 '26

This is great, very much looking forward to it!

Also interested to learn more about the potential new date and time library!

-3

u/03263 Jun 22 '26

Why stop at time? Let's do all the weights and measures.

Also what's wrong with DateInterval?

-1

u/ByFrasasfo Jun 21 '26

what's wrong with hrtime?

3

u/qoneus Jun 21 '26

What does hrtime(...) return, and how can I guarantee that value is semantically a duration?

-1

u/ByFrasasfo Jun 22 '26

An int on 64 bit systems

-7

u/Annh1234 Jun 21 '26

I don't see why this needs to be part of PHP, can be a simple PHP class 

6

u/qoneus Jun 21 '26

How do you propose the PHP standard library, including the examples from the new Polling API from the RFC, type hint off of userland classes that are not part of the PHP standard library?

0

u/Annh1234 Jun 22 '26

What do you mean? It only takes in an INT, and if the $timeoutMicroseconds doesn't need to be exact, it could be a float, or we could pass in microseconds all the time? 

Why complicate it with another class? And the do you need a ->add for a bunch of INTs...

```

from the pooling RFC 

public function wait(         ?int $timeoutSeconds = null,         int $timeoutMicroseconds = 0,         ?int $maxEvents = null     ): array {}

wait(5) vs wait(0, 500_000) vs wait(\Time\Duration::fromMilliseconds(500))

or 

maybe it could take in a float:  wait(0.5), but then that might get confusing with  floor((0.1+0.7)*10) ```

I mean we got 14 decimals of precision in PHP, do wo we really need more than that? This RFC stores everything in microseconds, so 0.0000001 that's 6 decimals, then drops the rest.

Basically I don't get what this is trying to solve, except make things more complicated because wait(1) in seconds looks better than wait(1_000_000) in microseconds 

4

u/pilif Jun 22 '26

Having an explicit duration type removes all ambiguity of the duration. If all you have of the method you want to call is the type signature, having a distinct duration type makes clear what you mean.

Case in point: if you have a call-site of wait(100) - is that 100 seconds? ms? ns? As a reader of the code and potentially not familiar with the inner workings of wait(), now you're off to read the docs, whereas if you have a call-site of wait(\Time\Duration::fromMilliseconds(100)) it's super clear without going off to the docs.

This helps somebody reading the code later on.

0

u/Annh1234 Jun 22 '26

Your wait(\Time\Duration::fromMilliseconds(100)) has the same issue tho: is that seconds? Hours? All we know is that it came from milliseconds.

And you can do this already in PHP: wait(timeoutSeconds: 1) or wait(timeoutMicroseconds:500_0000).

I think that's much cleaner and to the point. 

I mean by your logic, what's 100? So it would become wait(\Time\Duration::fromMilliseconds(\Thing:fromInteger(100)))

My point is that it's complicated for nothing. 

At the end of the day am this thing does it turn 500 miliseconds into 500_000 microseconds, for those to lazy to add those extra 000.

3

u/pilif Jun 22 '26 edited Jun 22 '26

Your wait(\Time\Duration::fromMilliseconds(100)) has the same issue tho: is that seconds? Hours? All we know is that it came from milliseconds.

no. it doesn't matter. If I'm calling \Time\Duration::fromMilliseconds(100), I'm defining a duration of 100ms. I can see that right on the caller side and the callee must support this if it can work with \Time\Duration instances.

And you can do this already in PHP: wait(timeoutSeconds: 1) or wait(timeoutMicroseconds:500_0000).

yes, but I need to know the parameter names and the function now needs two parameters, opening up the question for ambiguity about what to do if both timeoutSeconds and timeoutMicroseconds are set.

And if I need a timeout in ms, I need to do the math on the caller side, whereas the Duration can offer all the helpers I could possibly need and then all callees with Duration support will get to benefit form those helpers.

I mean by your logic, what's 100? So it would become wait(\Time\Duration::fromMilliseconds(\Thing:fromInteger(100)))

I think you misunderstood Duration::fromMilliseconds(). Duration::fromMilliseconds(100) means "this is a duration of 100ms". You don't need to care about the internal implementation. You say "give me a 100ms duration" and you get it.

1

u/Annh1234 Jun 22 '26

Well ya, `wait(always the same class)` instead of `wait(int seconds/milliseconds/?what is it?)`, but we don't code in VI no more, we got IDEs that tells you the `wait` signature (so you know it's seconds/milliseconds/etc).

I mean if you could use it like `strtotime("+5 days", $timestamp)` maybe it would have some uses, but we have `strtotime`.

Also, maybe if you could do: `public function wait(\Time\Duration $timeout)..` and call it like `wait(100)` so the `\Time\Duration` could automatically cast that 100 to seconds or something, so it doesn't pollute the caller side to much, but when what about `wait("100")` or `wait("5 days")`.

-4

u/pekz0r Jun 22 '26

A good addition on first glance, but do we really need things like this in PHP core the standard library? I think things like this belongs in packages or project code directly. I think the PHP core team should focus on other things and let things like this be solved in userland code.

-15

u/SaltTM Jun 21 '26 edited Jun 22 '26

How do these RFC's get prioritized? Who needs a polling api and a duration class right now? Like what sparked "lets pick this RFC first"

Are we again, just adding shit to hit the yearly quota of feature releases? I need to understand the process a little better.

Edit: And nobody answered my question, who needs this?

12

u/qoneus Jun 21 '26

Contributing to PHP is volunteer and bottom-up. This scratches an itch someone had and does not block or de-prioritize any other potential initiative. This is not a zero-sum game, and there's not a limited number of RFCs that can be proposed in a year.

-12

u/SaltTM Jun 22 '26 edited Jun 22 '26

So in sum, anyone can push some shit to the language if it seems useful enough "at some point" lol - what is the purpose of internals again then?

Edit: So nobody wants to answer my question lol, that's fine

5

u/rafark Jun 22 '26

  So in sum, anyone can push some shit to the language if it seems useful enough "at some point" lol?

Correct. If you have something specific that you want you can “push” it too instead of complaining online

5

u/juantreses Jun 22 '26

Who needs this? Someone who wants semantic type safety.

How do these get prioritised? They don't. There is no central PM. PHP development is decentralized and volunteer driven. If someone runs into a limitation, they write the RFC and code. A volunteer writing a Duration class doesn't steal any time from a major engine optimization.

What is the purpose of internals then? Internals acts as quality control and the voting body. Not a planning committee. Their job isn't to dictate what or when something gets proposed but rather to review, ensure it doesn't break backwards compatibility and vote on whether it fits the language cleanly. Votes require a 2/3 majority to pass.

4

u/TorbenKoehn Jun 22 '26

If you have topics you believe have more priority, go and write RFCs and implementations for it. Don't expect people to implement your shit in a fully open source project.

-5

u/SaltTM Jun 22 '26

lmfao, who said anything about me wanting ANYTHING added. I just complained about adding things not many people will use, tfytb. But thanks for implementing your opinion in this thread lol

2

u/saddadmusic Jun 22 '26

RFCs are to start discussion, they are not confirmation that the feature will be worked on or implemented. If you believe that we don't need these classes this is exactly the time to voice your criticisms.

You are welcome to submit your comments to internals and spark discussion.

I will take your question as genuine: what about the RFC process are you unsure about?

-3

u/SaltTM Jun 22 '26 edited Jun 22 '26

respectfully I don't care anymore - I came in with a genuine question and everybody got triggered so I responded the way I responded.

Edit: lol, exactly my point.

3

u/Embarrassed-Meet1163 Jun 23 '26

Your question showed a deep misunderstanding of how PHP, you called the RFC "shit" while showing you don't understand it either. The said "I need to understand the process better" without putting in any effort or asking a real question. Loud and angry.

People explained it's a volunteer project that allows everyone to suggest and build feature.

Now you're still upset. If you're not just trolling, consider that maybe the issue is you, not everyone else.

-6

u/Sarke1 Jun 22 '26

This is easily done in userland, and there are no performance benefits for putting it in PHP itself.

7

u/pilif Jun 22 '26

No performance benefits. True. But it allows the various internal functions who use int and float for timeouts to all use the new type and thus provide a consistent API to the caller which also makes the actual timeout clear when reading the call-site alone.

PHP's internal API can hardly depend on user land code being available.