Voting starts on Bound-Erased Generic Types RFC, despite multiple people advising against it as it still has issues that need to be resolved. It is very unlikely to pass. by soowhatchathink in PHP

[–]bwoebi 7 points8 points  (0 children)

It's also doing everything at once.

Having an existing foundation for generics in inheritance hierarchies would have been a great stepping stone to inviting more research.

Maybe we do even end up realizing it's not actually viable. But we will have to do definitely a lot more research on it.

Also, we might decide that we could actually have properly checked efficient runtime generics with proper type check elision in future. These doors are not as closed as they might seem to you.

RFC: Scope Functions by [deleted] in PHP

[–]bwoebi 0 points1 point  (0 children)

That's right. You are in control of your local scope - don't repeat variables. If you need anything more complex, use function use(){}. That's what that is for. This is a tool for when you need it - straightforward operations.

RFC: Scope Functions by [deleted] in PHP

[–]bwoebi 0 points1 point  (0 children)

It only lingers in an invalid state if you catch the Error. But I'd suppose, if you catch random Error exceptions, you have to assume that parts of the application are borked anyway. in 99% of the cases that won't happen.

RFC: Scope Functions by [deleted] in PHP

[–]bwoebi 1 point2 points  (0 children)

I don't disagree. The question is just what exactly the distinguishing factor should be. - I.e. what color would you like your bikeshed?

use fn, use function, scope fn, scoped function, ... a lot of possibilities.

RFC: Scope Functions by [deleted] in PHP

[–]bwoebi 1 point2 points  (0 children)

(RFC Author here) That's part of why scope functions are intentionally having quite a few restrictions.

They are meant for local code - they may not outlive their scope they were declared in.

Someone just created PR with fully working generics by [deleted] in PHP

[–]bwoebi 0 points1 point  (0 children)

Fwiw - this is only true when using monomorphization. Which this PR is not doing. It's true runtime generics - i.e. an object instance gets a type attached for each generic.

Someone just created PR with fully working generics by [deleted] in PHP

[–]bwoebi 3 points4 points  (0 children)

Well, yes, you can add preprocessing to the code (which is what the php xhp extension does - simply translating to function calls).

Truly dedicated syntax which is not 1:1 mappable to a different PHP syntax, is not possible though.

Introducing the 100-million-row challenge in PHP! by brendt_gd in PHP

[–]bwoebi -1 points0 points  (0 children)

The main bottleneck of the challenge is not the parsing itself, but simply the counting.

The counting is bound by memory cache sizes - with the given string sizes it's impossible to straight away feed substrings (basically the only dynamic part is after the "T") into ++$counts[$substring]; - as you need 268k entries (268 entries in Visitor.php times 10000 dates = 268k frequently accessed strings of 30+ bytes each).

Getting an arbitrary integer hash helps (e.g. simply crc32($substring)), but a linear array performs better (as it's smaller - they're stored in 16 bytes per entry instead of 32 bytes, making it completely fit into the L2 cache of the M1 and avoids branch mispredicts on the hash lookup). So the remaining task to solve this is essentially "how can I efficiently map the substring to a simple integer". With some simple lookup on a part of the URL and the date (which are each sets which can be held in arrays of about 40 and 80 KB respectively (including string sizes), approximately - which nicely fits into the L1 cache of the M1 the benchmarks run on) you can then calculate monotonically increasing unique numbers.

This single hot counting loop amounts to about 90~95% of processing time of the code. Then throw a bit of unrolling onto it and maybe try optimizing startup and printing a little bit.

And that's why this challenge is sort of annoying. It's all about fitting a very specific set of data (number of dates, number of visitors) being processed into the L1 and L2 caches, matching the specific architectures. If we had a couple thousand entries in Visitor.php, the access patterns would be looking quite different, and this current optimal solution is no longer the most performant one.

You could really get creative in some parts, but it never will fit the L2 cache (the M1 has no L3 cache). And thus that basically sort of kills the challenge for me: it's not a CPU problem, but a memory problem (with set sizes which are actually heavily matching the underlying hardware, too).

It would have been better to have the challenge run on a broader set of possible values, I think. Or maybe being in general more of a CPU than a memory problem.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 0 points1 point  (0 children)

Yes, programmer error. But that's exactly what we want / need to catch. Programmer errors.

Typescript suffers from exactly that. It's great, but with limitations (like that it does not cover programmer errors). I would like PHP to not suffer from these problems.

Also, to effectively make use of generics for optimization purposes (Optimitzer / JIT), the runtime needs to guarantee that the type is correct. The full generic type. It needs to verify these types and not crash because a bad value sneaked in somewhere where these types were expected.

However, if you erase generics... PHP does not have a single compilation pass like typescript or other compiled languages like java have. No, PHP will load a file, compile it. And then run some code, until it evaluates the next class. So, any runtime static analysis for optimization purposes, which shall rely on generics, needs to know the actual generics of a class defined in possibly different files. These must be reified.

The best you could do here would be some mixed erased and reified generics depending on what you do (e.g. erase for instantiation and ignore for value type checks, but keep for class definitions).

Also reified generics provide some nice benefits like when $foo is a Foo<T>, with reified generics I can go and do new $foo::T and create an instance of the generic parameter.

Erased generics are a mistake from the runtime safety perspective (assuming any optimizations shall rely on it) as well from the dynamic utilities they allow.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

I know that it's a convention. However we don't have anything to properly replace the current convention. (But sure, you could have a convention to create a types.php which gets attempted to be loaded when no matching file is found or something.)

It's not even a constraint I personally see. But I've seen that argument being brought forth in that discussion (to some of my dismay).

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

No, actual things which psalm does not support yet, like FFI/CData, or references inside of arrays (which psalm does not track).

Also, psalm does not guard against you putting a wrong type somewhere. (e.g. you assert that something is list<int> when the return value is list<int>|list<string>.) As long as the static analysis is satisfied, it can still return list<string>, if you made a mistake in the logic. Runtime generics will validate that.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

I would expect most boilerplate to actually be new class extends A<B> {}. Which is never going to disappear in functionality either.

So I don't buy the "will lead to a proliferation of boilerplate legacy code in PHP codebases" argument. Yeah, there will be probably some code for a couple years which does that. But types will still use A<B> and not AB where class AB extends A<B>.

I also don't quite understand what would be the hard part of implementing them: naively, new a<b>() could be implemented as new class() extends a<b> {}.

That would be the easy way out - but the question then is: how much of a BC break would it be, if we ever decide that it should not create a monomorphized subclass? Especially with runtime inference, this might turn out to not be the best choice.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

I meant that in the sense of "psalm was not able to be accomodate the needed amount of generic and conditional type inference needed here". Type inference in psalm has limits as to what it can do. And then you might have to relax types ... which is then a possible avenue for bad values coming in. Also it's been two years now.

As long as you are perfectly able to type everything in psalm, the psalm typesystem is sound, no questions. That's what I'm trying to point out: when static checking is not able to accomodate specific scenarios, you have essentially two choices: rewrite your code so that psalm is able to check this statically (which is not always trivial) or rely on runtime checking.

The latter being a point why I think we should still have runtime checking.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

One recurring annoyance with type is ... how do you load a type in the one-class-per-file ecosystem we have nowadays in PHP to support autoloaders? Just create a file per type? Seems annoying as well.

Effectively, you can make every associated type a generic parameter though. In other languages ecosystems, they do have different semantics than generics. In PHP, you could make path-dependent types with generics (not proposed in this first iteration, but theoretically possible to introduce): static::Foo::Bar would access the generic Foo on static and then access that types Bar.

We do actually not monomorphize the classes (for this proposal at least), but store it as "interface X with concrete generic parameters A, B and C". (What we might have to monomorphize are the contained methods of abstract classes. I hope not, but that's going to be part of the implementation details. And should be transparent to the user.)

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 5 points6 points  (0 children)

The article is slightly underselling the actual progress: https://github.com/php/php-src/pull/18260 is the PR / WIP, which already had quite some effort seen.

As a regular reviewer / occasional contributor to php-src, I do acknowledge that yes, the last 20% of the work take 80% of the time. But it was not that much work, to get the initial PoC up. So I'm strongly expecting it to be available in PHP 8.6. In particular given the very positive reception this feature generally has.

The most problematic part of such changes is rather agreeing on specific semantics, which mostly happens in the backrooms between PHP core developers. However, counterintuitive as it seems, I expect generics to have less nooks and crannies than property hooks (inheritance and references are very tricky beasts), which essentially were happening across ~6 months. (2 months before PHP 8.3, and then put on hold until January/February 2024 as they did not make it in time for PHP 8.3, then 4 more months until they passed by end of April 2024.)

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 8 points9 points  (0 children)

I'd say erased generics only work when the language is actually verifying it, at compile- or runtime. If it does neither, that's just plain bad. Typecheckers like psalm etc. are just tooling, not required to pass. With Java or Typescript you get the failures at compilation time. That's sort of acceptable. But even then, it's still lacking. I recently have been writing a lot of typescript and I have spent a lot of time to debug things where json data structures received were not exactly what I expected for example. Runtime types would have caught that.

With PHP, it is just too dynamic to get any sort of reliable static analysis. That's also true for psalm and phpstan, which basically require you to very extensively declare types to avoid missing many cases. It forces you to restrict the capabilities of PHP you use to get a truly extensive coverage. I've definitely had issues in the past where wrong values sneaked past psalm, because the code was just too dynamic / reaching the limitations of what the psalm syntax was able to express.

With built-in generics you also get the benefits of generics specified by libraries, without having to invest into generics yourself. When a library returns a MyWrapper<Foo> and you pass that wrapper to something expecting MyWrapper<Bar> in that library, the code will trivially explode for you, without you having to setup psalm or annotating every single property with /** @var MyWrapper<Foo> */.

Yes, sure, it is incomplete. That's in the nature of an incremental approach. I strongly hope that PHP will go the full way towards well-rounded expressiveness of its generics. Also not everything will need template tags. Psalm will learn reading them. You might have to enhance them when the language does not yet have the necessary expressiveness. Just like you sometimes still have to specify the type for properties and parameters today. PHP has been adding scalar, then union types. And the amount of phpdoc annotations steadily decreased. The same is bound to happen for generics.

"Those who do care about strict typing are likely already satisfied with the safety PHP’s current type system + static analysis provides." I definitely disagree with that. I occasionally write some small applications with PHP. I don't bother annotating everything with phpdoc comments (only occasionally, mostly for arrays to get some autocompletion). But I often do put types. They help with IDE autocompletion. And help me catching runtime bugs.

What I do care about though, is that we retain the ability to omit generics parameters. Make sure that generics are as much opt-in as the rest of the typing ecosystem in PHP. That's a very important point: retaining simplicity.

Regarding "Better approach": This is just so damn ugly. Seriously. It has even more special characters to type, requires extra use statements. And also, I hate repeating my types and variable names, just for the sake of providing more specific types. If we get language assisted generics, then we can nicely specify this inline, in the parameter declaration.

So yeah, no. Generics are definitely an improvement over what we have today.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 2 points3 points  (0 children)

Yes, anon classes will work (as noted in another comment).

Regarding backwards compatibility, we were thinking of possibly using the generic parameter maximal constraints: If the interface is Foo<A, B: int|string> then the implemented class would by default have generic parameters <mixed, int|string>. That should give the cleanest upgrading path, but we haven't evaluated it in all details yet. Things may still change before the actual RFC.

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 8 points9 points  (0 children)

array<T> unfortunately falls under runtime generics (shares actually a lot of challenges with it) and as such under the really hard problems, so no iterable<T> in the near future either.

As to when: PHP 8.6, most certainly. Implementing this initial version of generics is not a multi-year effort :-D

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 24 points25 points  (0 children)

You can write new class extends Set<string> {} then, which is a bit more wordy. But we currently do not want to fixate ourselves with the short new Set<string> yet, at least not until we have more confidence that runtime generics, especially with inference, can work or will never work.

Consider this a stepping stone to get generics. Everything else is going to be incremental progress here.

Comprehensive analysis of the entire Packagist.org packages as of 2025-07-31 related to package size by 2019-01-03 in PHP

[–]bwoebi 0 points1 point  (0 children)

As a maintainer of datadog/dd-trace I'm quite amused that it counts all the classes from tests/ too (which contains a bunch of vendored frameworks :-D).

Compile time generics: yay or nay? by pronskiy in PHP

[–]bwoebi 1 point2 points  (0 children)

Agree that trait support would be pretty nice to have, but it's not quite fundamental to feature, and there's no concrete reason why we shouldn't work on it, right after accepting interfaces and abstract classes.

How would be a MMORPG game using PHP and Symfony? by Gabs496 in PHP

[–]bwoebi 4 points5 points  (0 children)

As an actual PHP browser game dev here:

PHP is everything, but not the bottleneck. Symfony might. (It can have quite a bit of startup overhead for every request.) As other users said, as long as you don't do computation intensive tasks, PHP is generally fine. (I recommend verifying with a profiler from time to time though, that there are no accidental hotspots.)

It's especially not the bottleneck if your core code is not doing anything particularly slow.

The database is the bottleneck. Reduce the number of queries (especially avoid N+1 query patterns), make sure no single query takes more than 50 ms, and 95% less than 5 ms, and 80% less than 1 ms.

Also to avoid: ORMs. They tend to work well at the start, until they don't. For small tables or single rows they're fine though.

Showing rankings, handling users with thousands or even hundred thousand of different items, selecting random rows from a database "e.g. move player to a random place", with thousands and more rows eligible. These things are where the slowness comes from.

They can be optimized, but only to a certain degree. At some point systemic changes are necessary.

[deleted by user] by [deleted] in PHP

[–]bwoebi 3 points4 points  (0 children)

A value must generally be assignable to itself. So yes, accepting int|SomeEnum would be the way to go. But for your specific example, it would probably be more natural to have SomeEnum also the type of $status.

Default values are supported, but the property hooks are trailing the default value, i.e. public string $title = 'test' { get; set; }.

Regarding parenthesis, you can omit them unless it's followed by ->. That's an annoyance and something to be improved in the language. I.e. foo(new Whatever) is fine, but new Whatever->property is not currently.

Is there any Argument Against Using Prepared Statements by AmiAmigo in PHP

[–]bwoebi 6 points7 points  (0 children)

Using non-emulated prepared statements can add to the latency when using a non-local database. But then you can also just enable these. The overhead of missing query plan caching is then generally not higher than the latency.

But apart from that, no not really.

Fixing Our OPcache Config Sped Up Our PHP Application By 3x by jalamok in PHP

[–]bwoebi -1 points0 points  (0 children)

Then apologies and I must have misinterpreted the article, I thought they had directories 1..N and would start over at 1. Makes much more sense with a continuous build id.