PHP Internals News: Episode 86: Property Accessors

PHP Internals News: Episode 86: Property Accessors

In this episode of "PHP Internals News" I chat with Nikita Popov (Twitter, GitHub, Website) about the "Property Accessors" RFC.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode's MP3 file, and it's available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi I'm Derick. Welcome to PHP internals news, a podcast dedicated to explain the latest developments in the PHP language. This is episode 86. Today I'm talking with Nikita Popov about his massive property excesses RFC. Nikita, would you please introduce yourself?

Nikita Popov 0:32

Hi Derick, I'm Nikita, and I do work on PHP core development, on behalf of JetBrains.

Derick Rethans 0:39

This is probably the largest RFC I've seen in a while. What in one sentence, are you proposing to add to PHP here?

Nikita Popov 0:46

I would say it's an alternative to magic get and set, just for one specific property instead of all of them. That's the technical side. Maybe I should say something about the like motivation behind it, which is that since PHP seven four, we have type properties, that at least for me personally with that feature, the need to have this typical pattern of private property for storage, plus a public getter and setter methods, the main motivation for that has kind of gone away, because we can now use types to enforce any contracts on value. And now these getter and setter methods most if you like boilerplate. So the idea with accessors, at least my idea with accessors is that you really shouldn't use them. You should just have them as a backup option. You declare a public property in your class, and then maybe later, years later, it turns out that okay, that property actually requires additional validation. And right now if you have a public property, then you don't really have a good way of introducing that. Only way is to either break the API contract by converting the property into getter/setter methods where you can introduce arbitrary code, or by using magic get/set, which is definitely possible and persist the API contract, it's just fairly ugly.

Derick Rethans 2:09

You changes the public property that people could read into a private one. And because it's private, the set and get metric methods are being called.

Nikita Popov 2:18

Exactly.

Derick Rethans 2:19

This RFC is titled Property accesses, how do these improve on the situation?

Nikita Popov 2:24

So I think there are really two fairly orthogonal parts to this RFC. The first part is implicit accesses that don't have any custom behaviour, and just allow controlling the behaviour of properties a bit more precisely. In particular, the most important part is probably the asymmetric visibility, where you have a property that's publicly readable, but can only be set from within the class. So public read/ private write. I think that's a, maybe the most common requirement. The second part is where you can actually introduce some custom behaviour. So where you can say that okay, the get behaviour for this property looks like this, and the set behaviour, it looks like this. Which is essentially exactly the same as what magic get/set does, just for a single property.

Derick Rethans 3:10

For example, when you then do set, or you can add additional validation to it.

Nikita Popov 3:14

Exactly. Originally, you had a simple public property, then you can add a setter that checks okay this string cannot be empty.

Derick Rethans 3:23

Okay, what it's the syntax that you're proposing?

Nikita Popov 3:26

I went with these essentially the same syntax that's being used in C#. Looks like you write public foobar, and then you have this sort of semi colon you have a code block. And this code block contains two accessors, so then you have something like get, and another code block that specifies the get behaviour, and set, and the code block that specifies the set behaviour and so on.

Derick Rethans 3:52

The RFC talks about implicit and explicit implementations of these getter and setter accessors. What is the difference between them and how does it look different in syntax?

Nikita Popov 4:03

Yeah so the difference is, either you can write just get semi colon, set semicolon, that's an implicit implementation, or you actually specify a code block with real custom behaviour. To do the implicit implementation, you're saying that this is really a normal property, and PHP automatically manages the storage for you, is that you have this more fine grained control over how it works. Namely what you can do is you can say that you have get and private set. But that's a property that's publicly read only and internally writeable. You can write just get without set, in which case it's a real read only property both publicly and privately, or to be more precise, it's an init once property so you can assign to it once.

Derick Rethans 4:52

How do you keep track of the init once?

Nikita Popov 4:53

It's same mechanism as for Type Properties, where we distinguish between an initialized and an uninitialized property. You can assign to an uninitialized property, but you can't assign to an initialized one, if it's read only. The only maybe problem there is that this mechanism, requires that the property actually is uninitialized to start with, which means that for accessors you don't have any default values. To say there is no implicit default value, no implicit null value. If you want to have a default value the same as with type properties you have to specify it explicitly. Specifying a default value really only makes sense if the property is both readable and writable. For Read Only properties, if you specify the default then you will you can change that.

Derick Rethans 5:37

You have basically have created a constant.

Nikita Popov 5:39

Yes, it is essentially a constant.

Derick Rethans 5:41

You mentioned already, PHP seven four introduced type properties. How do these types interact with the setter and getter accessors?

Nikita Popov 5:50

I would say in the obvious way. The getter is required to return type of property, modulo the usual weak typing conversions, and the setter also checks before it's called whether the passed value matches the type or not. But enforces that matches the type.

Derick Rethans 6:08

This does mean that if you provide an explicit implementation for the set accessor, you also need to specify the parameter name?

Nikita Popov 6:15

No, or you can specify the parameter name, and if you don't then that's just passed in as the value variable. It's also inspired by how C# and Swift do it. I mean there are some possible variations here we could always require an explicit name, some people for that, or I also heard that some people would like to have the name of this implicit variable match the name of the property, instead of always being just value.

Derick Rethans 6:41

Would you have to specify the type though?

Nikita Popov 6:43

You wouldn't have to and you're actually not allowed to. So the accessor implementation is somewhat strict about not allowing you to do anything that would be redundant because otherwise, you know, there are quite a lot of extra things you could be adding everywhere.

Derick Rethans 6:56

That's the same way as marking a property as private. And then the accessors as private as well. Right?

Nikita Popov 7:03

Yeah exactly. So, then that will also say: if the property is already private you can't, again say that the accessors also private.

Derick Rethans 7:11

I think that's the wise thing, otherwise people go overboard with adding private and final and whatever everywhere anyway right.

Nikita Popov 7:18

One could argue that it's really not our business and this is a coding style question, but you know it's better to not leave people, with the option of doing stupid things.

Derick Rethans 7:28

I saw in the RFC that it is also possible to use references with the get accessor. Does this complicated implementation and the idea of this RFC, a lot, or just a little?

Nikita Popov 7:39

I think the important context to keep in mind here is that we already have magic get set, and the accessors are, like, largely based on their semantics. Magic getters already have this distinction between returning by value and returning by reference. The by reference return value is primarily useful for two cases. One and this is really the important one, is if you're working with arrays, any write operation on an array like setting an element or appending an element, those require that the getter returns by reference, because PHP will actually do the modification on the reference. Because some people asked about that. Why can't we just like get the array using the getter, then make the change and then assign back using the setter. That would theoretically work, but it would be extremely inefficient, and the reason is that this breaks PHP's copy on write mechanism. If the error is returned from the getter, then we have one array inside the property. And we have one copy of the array inside the property, and as the return value. Then we change the return value and the resource is now shared, we actually have to copy the whole array, and then we assign it back. So effectively what we do is we copy the array, we do single element change, and then we copy the array, we do a single element change and then we destroy the old array. That works in theory, but it's so inefficient that we would not want to promote this kind of usage.

Derick Rethans 8:42

The way around is of course, is having an implicit methods on the class to make this change to the array itself right?

Nikita Popov 9:10

That would be another option. Problem is that you will need a lot of methods, I mean it's not just a matter of setting a single element or unsetting an element, but you can also set like a deep element where you're not modifying the outermost array but, like, a multi dimensional array. You would actually have to pass through that information somehow as well. I don't think there is a simple solution to that problem beyond the reference based solution that we currently use.

Derick Rethans 9:34

I saw people arguing about not bothering with references in this new implementation at all, but I think you've now made a good case for keeping them.

Nikita Popov 9:42

Effectively not bothering with references just means not supporting that array use case. Which might be, maybe a reasonable limitation, especially if we like make a distinction and supported for the implicit accessor case where we can, you know, do internal magic to support that and not support it in the explicit accessors case. I mean, people were arguing that this reduces the complexity of the proposal, but it kind of also increases the complexity because now we are doing something else for the accessors and we're doing for the magic get/set, where we already have this established mechanism. I'm not really convinced by that.

Derick Rethans 10:20

And I also think it creates inconsistencies in the language itself because it does something different with an implicit or explicit accessor, as well as it being different between the original underscore underscore get magic method as well.

Nikita Popov 10:34

It's not a secret that I'm not a big fan of references, and I would certainly love to get rid of them, but it's a hard problem, and this array modification behaviour for magic get or for get accessors is certainly a large part of that problem, and I just don't have a good solution for it.

Derick Rethans 10:52

I don't either. The RFC also goes into great detail about inheritance and variance. Would you have a few words on that?

Nikita Popov 11:00

I think mostly inheritance works like inheritance does for methods, at least that's how it's supposed to work. Of course there are some interactions, because you can for example mix real properties and accessor properties. In which case, if you have parent accessor property, you can always replace it with a normal simple property, because normal properties they support all operations that accessor properties do. What you can't do is the other way around. If you have a parent normal property, then you can't replace that with an accessor property. And reason is that it does have some limitations. Not a lot, but there are some limitations. One of them is related to references, I mean, we're already talking about this topic. What the by reference get allows is taking a reference to the property, so you can do something like a reference equals the property. What you can't do is the other way around the property reference equals something else. So you can't assign a new reference into the property, that just doesn't work on a pretty fundamental level, because it would require an additional set handler for set by reference. As we don't particularly love references, adding a new mechanism to support that is not a very popular choice.

Derick Rethans 12:20

Variance wise, I guess, the same rules apply as for normal properties and property types?

Nikita Popov 12:27

Approximately. Properties are apparently invariant, so you can't change the type or I mean you can change it but it has to be an equivalent type. If you have a read only property, with only a getter, then the implementation makes the type covariant, which means you can use a smaller type in the child class. This is similar to how if you have a getter method, you could also give it a smaller type in the child class. The converse case, if you have a property that can only be set, then the type is contravariant, you can have larger type in the child class, though I should say that properties that can only be set are somewhat odd and really only supported for the sake of completeness, so maybe it might be worthwhile to drop the type specific behaviour there, because a set only property should already be really rare, and then set property with a contravariant inheritance that's like a edge case of an edge case.

Derick Rethans 13:24

Would it even make sense to support set only properties?

Nikita Popov 13:27

Not sure. So for the C#, implementation, I think they don't support this and there is a StackOverflow question about that, and people try to convince their, that they should support this, that the are really use cases. Currently the imagined use cases are along the lines of injecting values into a class, so using setter injection, just that now it's property based setter injection. Okay, I'll be honest I think it doesn't make sense.

Derick Rethans 13:55

To be fair, I don't think either. It would reduce the length of the RFC a little bit.

Nikita Popov 14:00

A little bit, yes.

Derick Rethans 14:01

Can you say a few words about abstracts, traits, private accessors shadowing and things like that. So a lot of complicated words, maybe you, you can distil that into something slightly simpler.

Nikita Popov 14:12

Well I think actually abstract properties are worth mentioning. In particular, the fact that you can now specify properties inside interfaces. If you have public properties, then it makes sense to have them really on the same level as public methods, so they are part of the API contract, and as such should also be supported in interfaces. Typically what the RFC allows is, you can't specify a simple property in the interface, but you can specify an accessor property, which tells you which operations have to be supported. So you can't have a property declaration that says, it just has a get accessor, or it has get and set. The implementation of course can always implement more, so if the interface requires get, then you can implement both get and set, but it has to implement at least get, either through an accessor offer another property. I think in most cases implementation will just be a normal property.

Derick Rethans 15:03

Because a normal property would implement an implicit get already anyway?

Nikita Popov 15:07

Yeah.

Derick Rethans 15:08

How do property accessors tie in, or integrate with constructor property promotion?

Nikita Popov 15:13

They are supported and promotion with the limitation that it's only implicit accessors. If you use constructor promotion, then you can specify your read only property in there, or property that is Public Read/ private write. You cannot specify a property with complex behaviour in there. This is mainly because it would mean that you embed large code blocks into the constructor signature, which is I think, pushing the limits of shorthand syntax, a bit. Like there is nothing fundamental that will prevent it, it's more a question of style.

Derick Rethans 15:50

The RFC talks a little bit about how, or rather what happens if you use foreach, var_dump, or an array cast on properties with explicit accessor. What are the restrictions here? Is something chasing from normal standard properties like we currently have.

Nikita Popov 16:03

I don't think so. So here is once again the case where we have this distinction between the implicit accessors, which are really just normal properties with limitations. So those show up in var_dump and array cast, foreach, as usual. And we have explicit accessors, which are really virtual properties, so they don't have any storage themselves. Any storage to use, you have to manage separately somehow. So, these don't show up in var_dump, foreach, and so on. Both these actual computed properties, they don't show up because that would require us to actually call all the accessors if you do foreach and that seems rather dubious to me.

Derick Rethans 16:44

How this will work for internal API's that some extensions use to access, like a list of all the properties, for say, for a debugger.

Nikita Popov 16:51

It'll work the same way as var_dump. I mean, in the end it's all, well it's not quite based on the same API's, but still, the answer is the same. You only get those properties that have some kind of backing storage, and those are only the ones that are either normal properties, or the ones with implicit accessors.

Derick Rethans 17:09

That means I need to go find out a way how to be able to read the ones with explicit accessors.

Nikita Popov 17:14

Yeah, if you want to. I don't think that the debugger should read those by default, because that means that doing a dump, will have side effects, which is not ideal, but maybe you want to have an option to show them.

Derick Rethans 17:26

That's something for me to think about, because I'm pretty sure people are going to want to see the contents of these properties, even in a debugger, even though that could mean that are side effects, which I'm not keen on.

Nikita Popov 17:36

I guess that's one of the, I would say advantages of using this over just magic get/set, because actually know which properties you're supposed to look at, with for magic get/set you just don't know at all.

Derick Rethans 17:51

The RFC talks a little bit about the performance impacts and although I saw the numbers I didn't actually read them, when preparing for this recording. What are the performance impacts for implicit accessors as well as explicit ones?

Nikita Popov 18:02

Impact is basically if you use implicit accessors that has similar performance to plain properties, performance is a bit worse. The reason is essentially that we have some limitations on caching. So we can't just cache it as if it were a normal property, because it could have asymmetric visibility. And we reuse the same cache slots for reads and writes. I've been thinking about maybe splitting that up but at least for now there is a small additional performance impact of using implicit accessors, but it's not really significant. On the other side if you use explicit accessors. Those are expensive, they are not quite as expensive as using magic get/set, but they are more expensive than using normal method calls. Reason is basically their normal method calls, they are very optimized, and they do not have to re enter the virtual machine, so we just stay in the same virtual machine loop, and we just switch to different stack frames. For magic get/set we actually have to like recursively call the virtual machine, because we don't have a good point to re enter it, at least based on our current API's. And we also have to deal with some additional stuff, particularly the fact that magic get/set and property accessor as both, they have recursion guards. Normally if you recurse methods in PHP, we don't do any checks about that. Xdebug does, but PHP itself doesn't, so you can infinitely recurse and PHP is fine. The only thing that happens is that at some point you'll run out of memory.

Derick Rethans 19:37

Or when extensions are loaded such as Xdebug, you'll actually still get a stack overflow.

Nikita Popov 19:41

So that's something we should still be addressing, at least the baseline behaviour that you can get to that memory limit error. For properties will set have recursion guards, which say that if you recursively access a property in magic get/set, that it will not call magic get/set again and instead, access the property as if they didn't exist.

Derick Rethans 20:01

Instead of throwing in an error?

Nikita Popov 20:03

Yeah. For property accessors I'm actually throwing an error on recursion, and the reason for that is if we didn't throw an error, then this would end up accessing dynamic property of the same name as the accessor, which would technically work, but it's very likely not what the programmer actually intended. So it's going to be really inefficient because you actually have to allocate space for the dynamic properties and access for those. So if you wanted to have some kind of backing storage for the property, then you should just explicitly declare it and access that, rather than accessing something with the same name and implicitly creating a dynamic property.

Derick Rethans 20:41

Yeah, that sounds all very complicated.

Nikita Popov 20:44

It's cleaner to just make it an error and let the programmer fix it, instead of PHP try to fix it for you.

Derick Rethans 20:51

Are there any BC considerations about the introduction of property accessors?

Nikita Popov 20:55

Not strictly, but I'm sure that it's going to break, various assumptions for people, or at least in the sense that, right now, most assumptions should already be broken through magic get/set. I mean you can always have this kind of magic behaviour. If we have accessors this is probably going to be a lot more common, and people will have to deal with things like properties being publicly readable, but privately writable much as because someone very rarely manually implements that behaviour, but because the language though has native support for it and it's going to be common.

Derick Rethans 21:28

We spoke a little bit about all the different sticking points in his RFC, for example with references, but there's one other thing and I think it's an argument you make somewhere on the bottom of the RFC, that there is a separation between implicit and explicit property accessors. I'm wondering whether it would make sense to consider adding whether the implicit part of this RFC first and then maybe later look at adding explicit property accessors.

Nikita Popov 21:54

That's really the main sticking point, and also my own problem with the RFC. I mean, you mentioned at the very start, that this is a very long RFC and still a little bit incomplete so it's going to be longer. It's a fairly complex feature that has complex interactions with other features in PHP. The implementation is actually, maybe less complex, then you think, given the RFC length. The main concern I have is that, at least for me personally the most useful part of the RFC, are the read only properties. The read only properties and the like Public Read, Private Write properties. I think these two cover like 90% of the use cases, especially because if you have a property that is only publicly readable, then you don't really have to be concerned about this case where you have to, later on, add additional validation. I mean after all the property is read only, or you control all the sets because they're private. There is no danger of introducing an API break, because you have to add additional validation. I think like the largest part of the use case of the whole accessors proposal will be covered by these two things, Or maybe even just one of these two things, that's a bit of a philosophical question. There are some people who think we should have just public read / private write and no proper read only properties, because that like looks the same from the user perspective, but still gives you more flexibility. I think that's like the most important use case, and we could implement that part with a lot less language complexity. So the question is really does it make sense to have this full accessor proposal, if we could get the most useful part as a separate simpler feature, and, well, I heard differing opinions on that one. I was actually pretty surprised that their reception of the on like a full accessors proposal was fairly positive. I kind of expected more pushback, especially as, this is the second proposal on the topic, we had earlier one with, like, similar syntax even though different details, and that one did fail.

Derick Rethans 24:02

How long ago was that?

Nikita Popov 24:03

Oh that was quite a while actually, at least more than five years.

Derick Rethans 24:06

I think that the mindset of developers has changed in the last five to 10 years, like introducing this 10 years ago would never happened, or even typed properties, right. It would never have happened.

Nikita Popov 24:17

That's true.

Derick Rethans 24:19

Do you have any idea when you're going to put us up for a vote? Because, of course, PHP 8.1 feature freezes coming up in not too far away from now.

Nikita Popov 24:28

Yeah, I'm not sure about that. I'm still considering if I want to explore the simpler alternatives, first. There was already a proposal. Another rejected proposal for Read Only properties, probably was called write once properties at the time. But yeah, I kind of do think that it might make sense to try something like that, again, before going to the full accessors proposal or instead.

Derick Rethans 24:54

Do you have anything else to add?

Nikita Popov 24:56

What are your thoughts on this proposal, and the question at the end?

Derick Rethans 24:59

I quite like it, but I also think that it might make sense to split it up. I'm always quite a fan of splitting things up in smaller bits, if that's possible too, and still provide quite a lot of use out of it. And that's why I was asking whether it makes sense to split it up into the implicit part and the explicit part of it, especially because it makes the implementation and the logic around it quite a bit easier for people to understand as well.

Nikita Popov 25:24

It's maybe worth mentioning that Swift also has a similar accessor model but it is more like a composition of various different features like read only properties, properties with asymmetric visibility, and then finally properties with like fully controlled, get and set behaviour rather than this C# model where everything is modelled using accessors with appropriate modifiers. So there is certainly precedent in other languages of separating these things.

Derick Rethans 25:55

Something to ponder about, and I'm sure we'll get to a conclusion at some point. Hopefully some of it before PHP eight one goes and feature freeze, of course. We've been chatting for quite a while now, I think we should call it the end for this RFC. Thank you for taking the time today to talk about property accessors.

Nikita Popov 26:11

Thanks for having me, Derick.

Derick Rethans 26:12

Thank you for listening to this installment of PHP internals news, a podcast, dedicated to demystifying the development of the PHP language. I maintain a Patreon account for supporters of this podcast as well as the Xdebug debugging tool. You can sign up for Patreon at https://drck.me/patreon. If you have comments or suggestions, feel free to email them to derick@phpinternals.news. Thank you for listening and I'll see you next time.



Interview #2 with Joe Ferguson

We welcome Joe Ferguson back to catch up with us about PHP, his column “The Workshop”, and more

Topics Covered

  • Virtual conference experiences.
  • Looking forward to in-person events.
  • Laravel Homestead, which Joe maintains. Uses and tradeoffs versus Docker.
  • Docker Performance on Mac
  • Local Development Environments
  • Goals for his Workshop, eventually looking at Docker Swarm and Kubernetes.

The post Interview #2 with Joe Ferguson appeared first on php[architect].


237:The Case Of Cyclomatic Complexity

Links from the show:

This episode of PHPUgly was sponsored by:

Cloudways, a managed cloud hosting platform built for your PHP projects.
If you simply wish to focus on your business, Cloudways is the way to go. They take over server management and security and free up time that you can dedicate to growing your business and acquiring new clients.
The Platforms offers a choice of IaaS partners (AWS, Google Cloud, Digitalocean, Linode, and Vultr). In addition, you get a performance-optimized stack, managed backups, and staging environment where you can test your code before pushing it to live servers.
Best of all, Composer and Git come pre-installed so you can get your projects up and running quickly.
All this power, simplicity, and peace of mind falls right with their brand slogan - Moving Dreams Forward
Be sure to visit cloudways.com/en/php-hosting.php today. Sign up using the Promo code PHPUgly and get a $25 credit.

PHPUgly streams the recording of this podcast live. Typically every Thursday night around 9 PM PT. Come and join us, and subscribe to our Youtube Channel, Twitch, or Periscope. Also, be sure to check out our Patreon Page.

Twitter Account https://twitter.com/phpugly

Host:

Streams:

Powered by Restream

Patreon Page

PHPUgly Anthem by Harry Mack / Harry Mack Youtube Channel


PHP Internals News: Episode 85: Add IntlDatePatternGenerator

PHP Internals News: Episode 85: Add IntlDatePatternGenerator

In this episode of "PHP Internals News" I discuss the Add IntlDatePatternGenerator RFC with Mel Dafert (GitHub).

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode's MP3 file, and it's available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi I'm Derick, welcome to PHP internals news, the podcast, dedicated to explain the latest developments in the PHP language. This is episode 85. Today I'm talking with Mel Dafert about the "Add Intl Date Pattern Generator RFC" that she's proposing for inclusion into PHP 8.1. Mel would you please introduce yourself?

Mel Dafert 0:35

Hello, I am Mel. I've been working professionally with PHP for about three years. Recently I started reading the internals mailing list in my free time, but this is my first time contributing.

Derick Rethans 0:46

What made you think starting to read the PHP internals mailing list?

Mel Dafert 0:50

I generally like reading mailing lists and issue trackers. And since I work with PHP, it was interesting to read what's, what's happening.

Derick Rethans 1:02

That's what I'm trying to read this podcast as well of course; explaining what happens in the PHP development. But let's get to your RFC. What is the problem that you're trying to solve for this?

Mel Dafert 1:14

Currently, PHP exposes the ability for locale dependent date formatting with the Intl Date Formatter class. It is basically only three options for the format: long, medium and short. These options are not flexible enough in some cases, however. For example, the most common German format is day dot numerical month, dot long version of the year. However, neither the medium nor the short version provide this, and they use either the long version of the month, or a short version of the year, neither of which were acceptable in my situation.

Derick Rethans 1:47

I realize that you basically ran into a problem that PHP wasn't doing something you wanted to do it. But what made you actually wanting to contribute this?

Mel Dafert 1:57

I ran into this exact problem at work where I wanted to format dates in this specific way. After some research, I found out that ICU, the library that powers Intl Date Formatter, exposes exactly this functionality already. It would be relatively easy to wire this up into PHP and expose it there as well. I also found in a bug report that other people had this problem as well, so I decided to try my best at hacking at the PHP source and make it available to everyone, using PHP.

Derick Rethans 2:25

Had you ever seen a PHP source code before?

Mel Dafert 2:28

I don't think so. No.

Derick Rethans 2:29

But you are familiar with C a little bit?

Mel Dafert 2:32

On a very basic level, yes.

Derick Rethans 2:34

As part of this RFC What are you trying to suggest to add to PHP?

Mel Dafert 2:39

ICU exposes a class called date time pattern generator, which you can pass a locale and so called skeleton and it generates the correct formatting pattern for you. Skeleton just includes which part are supposed to include it, to be included in the pattern, for example the numerical date, numerical month, and the long year, and this will generate exactly the pattern I wanted earlier. It is also a lot more flexible, for example the skeleton can also just consist of the month and the year, which was also not possible so far. I am proposing to add a Intl Date Pattern Generator class to PHP, which can be constructed for locale, and exposes the get best pattern method that generates a pattern from a skeleton for that locale.

Derick Rethans 3:22

The skeletons, what do you specify in these skeletons?

Mel Dafert 3:27

It's a similar format to the pattern itself. For example, it's lowercase y lowercase y uppercase M uppercase M, would give you only the year and only the month, if I'm correct, that's exactly what the skeleton looks like.

Derick Rethans 3:43

But it puts it in the right order?

Mel Dafert 3:45

It puts it in in the right order, and in some cases also adds extra characters, or even changes the format slightly, depending on the locale.

Derick Rethans 3:55

So it is a bit of a flexible way to tell the Intl extension to format them in a slightly more, well how do you say this, a slightly more intelligent way than what the standard, long, short and medium constants do for you.

Mel Dafert 4:11

Exactly.

Derick Rethans 4:12

Why is it so important that you get these formats, right, or rather I should say, how do these locales influence formats and why is this important?

Mel Dafert 4:21

There are conventions of how to format dates and times vary rather strongly between languages and country. In Austria, for example, nobody would expect to understand the US format of month slash day last year. I assume people in England may have the same issue.

Derick Rethans 4:38

I think everybody has that issue except for people in the US.

Mel Dafert 4:42

But that only shows the importance of using a format that people are used to and understand. Other languages like mainland Chinese even have the words for day and month included in the format, as far as I understand. I don't speak Chinese.

Derick Rethans 4:59

Neither do I, but a long time ago when I, when I added the date time support, not Intl, but PHP standard date time support, I also looked at locales that operating systems have. And even these locales, which is not something that Intl uses now, also encode these extra characters at least for Japanese, so that was interesting to see there as well.

Mel Dafert 5:22

There is a lot of sometimes somewhat unexpected formats.

Derick Rethans 5:27

And I think German sometimes once the add the in front, and sometimes behind and things like that. I know there's lots of little intricacies, yes. I see that he RFC makes an argument about which name to pick for the new class. Can you elaborate on the two different options that are?

Mel Dafert 5:44

Yes, this is certainly for us and what I would call bike shedding. ICU has something of an inconsistency in its naming. The formatting class is called date formatter. And the pattern generator class is called Date Time pattern generator.

Derick Rethans 6:00

So it has the extra word time in it?

Mel Dafert 6:03

Between some inconsistency with Intl Date Formatter, which already exists in PHP, and the Intl Date Time pattern generator, or if we make sure PHP is internally consistent and omit the time in all cases. So far consensus seems to lean towards the second option. This is also what the Hack people decided to use.

Derick Rethans 6:24

And I believe that's the one you are wanting to go with in this RFCs as well, right?

Mel Dafert 6:28

Exactly. So far, everybody voted slide, or like express themselves to slightly favour the version without time. So that's the one I'm going with.

Derick Rethans 6:40

Of course, as you mentioned, this is a fairly small change to it, but the RFC talks a bit about things to add in the future, because I believe you weren't suggesting to add all of these Intl functionality straightaway. What is this future scope?

Mel Dafert 6:55

ICU would also expose more methods around the skeletons, for example, turning a pattern back into its skeleton, or building a list of skeleton and then mapping to the patterns from scratch. That's what you would do in theory if you added your own special locale to this.

Derick Rethans 7:17

I'm not sure how to do that with PHP actually, but I think ICU allows you to build your own basically files with settings right?

Mel Dafert 7:25

Exactly. This is omitted all of this, for simplicity, and because they couldn't think of a use case for it, personally, at least. If someone does need them, they could easily be added. It would just be a bunch of extra methods on the, on the class.

Derick Rethans 7:43

I know that ICU has so much functionality that hasn't been exposed to PHP, because there's just so much of it right?

Mel Dafert 7:50

Extremely, yes. I did see that Hack decided to expose all of them, like all the methods that the class has, but I really don't see the use of having to document and test all of these methods when really only one is going to be used. So I've decided to just go for the one that I can actually see people using.

Derick Rethans 8:14

And it is always easy to get smaller parts added to PHP than big things, to begin with.

Mel Dafert 8:21

Exactly.

Derick Rethans 8:22

How has the reception been so far?

Mel Dafert 8:24

I haven't gotten feedback from too many people, but it seems positive so far. A few people that did give some feedback were constructive and seem to seem to like the idea of adding this.

Derick Rethans 8:36

I reckon outside of English speaking countries this is quite an important thing to actually support, especially as we just discussed, people are picky about how these things are formatted.

Mel Dafert 8:46

Very picky.

Derick Rethans 8:48

So the name that you're going for would be Intl Date Pattern Generator, would it also support patterns for the time itself?

Mel Dafert 8:55

Of course, just like Intl Date Format also support formatting time.

Derick Rethans 9:02

It would be strange if it didn't, to be honest.

Mel Dafert 9:04

Yeah.

Derick Rethans 9:05

When do you think you're going to put us up for a vote for inclusion to PHP 8.1?

Mel Dafert 9:10

I think I sent out the first email about two weeks ago for opening the discussion. So I was planning to send out the heads up, either today or tomorrow, and opening the vote after that.

Derick Rethans 9:23

Okay. To be fair, I think there is very little controversy in this one, so it would surprise me if it didn't pass.

Mel Dafert 9:30

That's reassuring. I am somewhat anxious about them.

Derick Rethans 9:33

It's not controversial, it is an, it is perhaps a niche thing but it is something that is useful, so I can't see people really be opposing to this. To be fair, I think it looks like just an omission from when the Intl extension was written in the first place.

Mel Dafert 9:48

That's true. It might have not been supported in ICU at that point.

Derick Rethans 9:54

That is a good point as well because I think the Intl extension came with PHP five three, or five four, which I think is now eight years ago or something like that.

Mel Dafert 10:04

I think, I think ICU might have not had it at the end. It's an old word, like it's an all supported versions of PHP.

Derick Rethans 10:13

That is good to know. Would you have anything else to add?

Mel Dafert 10:16

No, I think that's it.

Derick Rethans 10:17

Thank you for taking the time today to talk to me about your proposal to add the Intl date pattern generator to PHP 8.1

Mel Dafert 10:25

Of course. Thank you for having me.

Derick Rethans 10:29

Thank you for listening to this installment of PHP internals news, a podcast dedicated to demystifying the development of the PHP language. I maintain a Patreon account for supporters of this podcast as well as the Xdebug debugging tool, you can sign up for Patreon at https://drck.me/patreon. If you have comments or suggestions, feel free to email them to derick@phpinternals.news. Thank you for listening and I'll see you next time.


World of Warcraft, Kool Aid, and Wizards

In this episode, Jake and Michael discuss developing multi-step wizards using Alpine.js and Tailwind, the perils of supporting non-evergreen (Safari) browsers, and appropriate use of input modes and autocomplete.

This episode is sponsored by Workvivo - the employee communication platform to excite, engage and connect your entire company.

Show links

236:Memory Leaks

Links from the show:

This episode of PHPUgly was sponsored by:

Cloudways, a managed cloud hosting platform built for your PHP projects.
If you simply wish to focus on your business, Cloudways is the way to go. They take over server management and security and free up time that you can dedicate to growing your business and acquiring new clients.
The Platforms offers a choice of IaaS partners (AWS, Google Cloud, Digitalocean, Linode, and Vultr). In addition, you get a performance-optimized stack, managed backups, and staging environment where you can test your code before pushing it to live servers.
Best of all, Composer and Git come pre-installed so you can get your projects up and running quickly.
All this power, simplicity, and peace of mind falls right with their brand slogan - Moving Dreams Forward
Be sure to visit cloudways.com/en/php-hosting.php today. Sign up using the Promo code PHPUgly and get a $25 credit.

PHPUgly streams the recording of this podcast live. Typically every Thursday night around 9 PM PT. Come and join us, and subscribe to our Youtube Channel, Twitch, or Periscope. Also, be sure to check out our Patreon Page.

Twitter Account https://twitter.com/phpugly

Host:

Streams:

Powered by Restream

Patreon Page

PHPUgly Anthem by Harry Mack / Harry Mack Youtube Channel


PHP Internals News: Episode 84: Introducing the PHP 8.1 Release Managers

PHP Internals News: Episode 84: Introducing the PHP 8.1 Release Managers

In this episode of "PHP Internals News" I converse with Ben Ramsey (Website, Twitter, GitHub) and Patrick Allaert (GitHub, Twitter, StackOverflow, LinkedIn) about their new role as PHP 8.1 Release Managers, together with Joe Watkins.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode's MP3 file, and it's available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi, I'm Derick, welcome to PHP internals news, a podcast, dedicated to explaining the latest developments in the PHP language. This is episode 84. Today I'm talking with the recently elected PHP 8.1 RMs, Ben Ramsey and Patrick Allaert. Ben, would you please introduce yourself.

Ben Ramsey 0:34

Thanks Derick for having me on the show. Hi everyone, as Derick said I'm Ben Ramsey, you might know me from the Ramsey UUID composer package. I've been programming in PHP for about 20 years, and active in the PHP community for almost as long. I started out blogging, then writing for magazines and books, then speaking at conferences, and then contributing to open source projects. I've also organized a couple of PHP user groups over the years, and I've contributed to PHP source and Docs and a few small ways over the years, but my first contributions to the project were actually to the PHP GTK project.

Derick Rethans 1:14

Oh, that's a blast from the past. You know what, I actually still run daily a PHP GTK application.

Ben Ramsey 1:21

Oh, that's interesting. What does it do?

Derick Rethans 1:23

It's Twitter client.

Ben Ramsey 1:24

Did you write it.

Derick Rethans 1:26

I did write it. Basically I use it to have a local copy of all my tweets and everything that I've received as well, which can be really handy sometimes to figuring out, because I can easily search over it with SQL it's kind of handy to do.

Ben Ramsey 1:41

It's really cool.

Derick Rethans 1:42

Yep, it's, it's still runs PHP 5.2 maybe, I don't know, five three because it's haven't really been updated since then.

Ben Ramsey 1:49

Every now and then there will be some effort to try to revive it and get it updated for PHP seven and eight, but I don't know where that goes.

Derick Rethans 1:59

I don't know where that's gone either. In this case, for PHP eight home there are three RM, there's Joe Watkins who has done it before, Ben, you've just introduced yourself, but we also have Patrick Allaert, Patrick, could you also please introduce yourself.

Patrick Allaert 2:13

Hi Derick, thank you for the invitation for the podcast, my name is Patrick Allaert. I am a Belgian freelancer, living in Brussels, and I spent half of my professional time as a IT architect and/or a PHP developer, and the other half, I am maintaining the PHP extension of Blackfire, a performance monitoring solution, initiated by Fabien Potencier.

Derick Rethans 2:39

I didn't actually know you were working on that.

Patrick Allaert 2:40

I'm not talking much about it but more and more. So I succeeded to Julian Pauli, who by the way was also released manager before so now I'm working with Blackfire people. It's really great, and this gives me the opportunity to spend about the same amount of time developing in C and in PHP. This is really great because at least I don't. It's not just only doing C. I, at least I connect with what you can do with PHP. I see the evolution from both sides. And this is really great. It's great, it's also thanks to you Derick, you granted me access to PHP source codes. That was to contribute to testfest something like 12/13 years ago, it was, CVS, at that time.

Derick Rethans 3:28

CVS, so now I remember that. Basically, what you both of you're doing is making me feel really old and I'm not sure what I like that or not. I think we all have gotten less head on our heads and greyer in our beards. In any case, what made you volunteer for being the PHP 8.1 RM?

Patrick Allaert 3:46

In my case, I think there were two two reasons is that PHP really brings a lot to me in my career, everything is built around my expertise in PHP and its ecosystem. By volunteering as a release manager. I think I can give something back to PHP, because the last time I contributed to source code of PHP, it was really years ago. If I remember it was array to string conversion that was very silent and not emitting any notice; now it's warning. In the meantime, so I think that was PHP 5.0,

Derick Rethans 4:22

Ages ago.

Patrick Allaert 4:23

Ages ago. Indeed. I was quite passive I was mostly reading on PHP internals, and most of the time now that is quite big so if, if I had to say something I could always see some someone who already just said the same thing so I was not saying: plus one. This is one of the reason and the second one I think is that I think it's kind of a unique opportunity, and I can learn a couple of things. I think, on day one when the Rasmus gave me the access, saying that I can do to OAuth authentication on SSH and that was: okay, day one I already learned something, so that was really cool.

Derick Rethans 4:58

And you Ben, I think you tried to be the PHP eight zero release manager as well at some point. That didn't happen at the time, but you've tried again.

Ben Ramsey 5:06

I almost didn't try again. I don't know why but when Sara announced it this year, I thought about it, and I don't know, I tossed it around a little bit, but I've been wanting to do it for a long time and I've noticed as Joe Watkins recently put it on a blog post that we need to help the internals avoid buses. So since this is a programming language that I've spent a lot of time with just as Patrick mentioned, both in and out of my day jobs. I want it to stick around to thrive. Since I'm not a C guru, but I do have a lot of experience managing open source software. I wanted to volunteer as a release manager, and I hope that I can use this as an opportunity to inspire others who might want to get involved, but don't know how.

Derick Rethans 5:55

And of course you just mentioned Joe, Joe Watkins, who is the third PHP release manager for 8.1, and that is a bit of a new thing because in the past, when the past many releases I can remember you've only had two most of the time.

Ben Ramsey 6:09

I think, on the mailing list that came up early on in the thread, and there was a general consensus, I think, consensus may be the wrong word, but there were a couple of people who spoke up and said that they wouldn't mind seeing multiple rookies or mentees or whatever you want to call us, and Joe when he volunteered to be the veteran, and he was the only one who volunteered as the veteran. He said that he would take on two. And so that's that's why Patrick and I are both here and I think that's a good idea, because it will continue to help, you know, us to avoid buses.

Derick Rethans 6:46

Yep. And if you're three, you only have once every 12 weeks. Whereas of course, in my case doing it for PHP 7.4 it's every four weeks, because it's me on my own, isn't it. Which is unfortunate that these things happen because people get busy in life sometimes. Getting started being a PHP release manager can be a bit tricky sometimes because just before we started recording, I had to add you to a few mailing lists. Do you think you've now have access to everything, or what do you need access to to begin with?

Patrick Allaert 7:18

There is the documentation about release managers, what are you supposed to do, and, and there is an effort of documentation, what you have to ask, in terms of access, and that's great. We are probably going to contribute with our findings to, to improve the documentation. Once you did a bit of the setup, mainly needs to access the servers. You should also know what is the workflow and what are the usual tasks. This is mentioned in the documentation, but I think it would be better to have a live discussion with someone that already did it. The fact that we are doing it with Joe Watkins, who is not only a release manager of 8.1, but also previous release manager, that should be really smooth, to, to see what the the orders and what is the routine to do. To do so, why do you think Ben?

Ben Ramsey 8:16

I agree. I think that, I mean we've only just gotten started. It's only this I believe is what was it two weeks ago that we, that this was announced. So this is the first time that Patrick and I have actually spoken face to face. Hi, Patrick! We've communicated by email and slack. I'm sorry not Slack, StackOverflow chat. Joe has given us a lot of good pointers. I feel like some of the advice he's given his been really good, but it's like Patrick said, we haven't really had like a live, like one on one chat, or face to face chat, where we could kind of get caught up on things and understand what the flow looks like. So last week I started going through a lot of the pull requests on GitHub. And I've been tagging them as bug fixes or are enhancements, and there's also an 8.1 milestone that I've been adding to a lot of the tickets, are the pull requests, and I've merged a few of them, but I think that I've merged them a little prematurely. So there were some funny things that came up out of that. I do plan to blog on this, but one of Nikita's comments in the Stack Overflow chat was, you've just made it your personal responsibility to add tests for uncovered parts of the Ristretto255 API.

Derick Rethans 9:40

Right, exactly say because I'm doing release management for PHP seven four. I don't do any merging at all. The only thing I'm doing is making the packages, and then coordinating around them. I'm not even sure whether it is a responsibility of a release manager to do.

Ben Ramsey 9:55

It may not be a responsibility. I felt like it was helpful maybe to go ahead and take a look and see where things were trying to follow up with people, to get them to respond if something had been sitting there for two weeks or so without any kind of movement. I would, you know, leave a message saying what's the status of this.

Derick Rethans 10:19

I know from the documentation that we have on our Release Management process. And many of these steps actually been replaced by a Docker container that actually builds the binaries, so I'm not sure whether Joe I've mentioned that to you yet, because I'm not sure whether that was around when he did release management, the previous time.

Ben Ramsey 10:36

Right, it wasn't around either when he did release management, but he's also mentioned that he would like for us to learn how to do it without the Docker container, even if we do plan to use the Docker container.

Derick Rethans 10:48

That's fair enough, I suppose. I have never had to do that, but that there you go. Now, what is the timeline like?

Patrick Allaert 10:56

In terms of timeline I think the very first thing is being all three release managers having live discussion to define what, what we should do, when we should do, and how. This way we clearly knows our responsibility and the sequence, and also how we are going to organize. Do we do every three releases? We share the task? How are we going to do the work together. In terms of timeline I think the very first release is going to happen in June, if I remember correctly. I set up an agenda sheet with ICAL so that we all can put that in our calendar, nothing really clear on my side.

Derick Rethans 11:41

From what I can see from the to do list that the first alpha release is June, 10, which is exactly a month away from when we are recording this.

Patrick Allaert 11:51

Right, yeah, it's one month come down before the very first one. I think it might be great that the very first release being made by by Joe, so that we can really see every single step he's doing, so that we can do the same. However, I guess it's kind of a shared responsibility to do triage of bugs and pull requests.

Ben Ramsey 12:14

Right. I think there is some desire among the community to see these releases in real time at least a few of them. So I'm going to try to encourage us to stream some of them maybe live, or at least record it and put it up somewhere for people to kind of just see the process to demystify it, so to speak.

Derick Rethans 12:35

I actually tried it a few months ago to record it, but there were so many breaks and pauses and me messing things up, and me swearing at it, that I had to throw away the recording. I mean the release went out just fine but like absolute as again... I can imagine the first few times, you're trying this there might be some swearing involved, even though you might not vocalize that swearing.

Ben Ramsey 12:56

Oh I'll vocalize it.

Derick Rethans 12:58

Fair enough. This is something that is that you're going to have to do for the next three and a half years. Do you think you'll be able to have the time for it in another three years?

Ben Ramsey 13:08

I mean for myself I I'm committed to it, I definitely believe that I'll have the time over the next three and a half years, and I'll make the time for it.

Derick Rethans 13:18

What about you, Patrick?

Patrick Allaert 13:20

Exactly the same. I think it's the least that I can do to PHP, in terms of contributing back, there will be some changes because I it's not like it's, it's not like the infrastructure is something that doesn't change, like for example recently, GitHub, being more having more focus rather than our Git infrastructure. So the changes that will happen, we will have to adapt, I have the impression that release manager has to, every time it's adapting to change this, and that will be very interesting.

Derick Rethans 13:53

Luckily we haven't had too many. The only thing I had to change with a change from git dot php.net to get up, was my local remote URLs. So there wasn't actually a lot to do, except for running git remote set-url. I was pleasantly surprised by this because if anything messing around with Git isn't my favourite thing to do.

Ben Ramsey 14:14

Also, merging is a little bit more streamlined now you don't have to go to qa.php.net to do that.

Derick Rethans 14:21

I've never done anything without

Ben Ramsey 14:23

Really? Oh, I guess you would commit directly to git.php.net?

Derick Rethans 14:27

Yep.

Ben Ramsey 14:28

If there were PRs on GitHub, the only way to merge them well, probably wasn't the only way but one way to merge them was to go to qa.php.net, and if you were signed in with your PHP account, you were able to see all the pull requests, and choose to merge them.

Derick Rethans 14:46

Yep, also something I've never done as an RM. The only way how I have reacted with pull requests is commenting on the pull requests, and I wouldn't merge them myself. With the only exception of security releases where you need to cherry pick from certain branches into your release branches. I'm not always quite sure about it as the responsibility for release managers actually do the merging into the main branches. From what I've understood is it's always the people that made the contributions, who just merge themselves, and you then sometimes need to make sure that they merge into the right branch instead of just master, which is what, as far as I know, the, the buttons on GitHub do.

Ben Ramsey 15:21

Well the individual contributors, in this case, if they're doing like a bug fix or something, most of them, or many of them aren't don't have permission to do the merging, so someone else has to merge it, like, often I see Nikita merging, a lot of the pull requests.

Derick Rethans 15:37

Maybe I've just been relying on Nikita to do that then. I'm not sure how, bug fixes are merchants debug fig branches. I think it's usually been done by people that have access already anyway, because it's often either Nikita or Cristoph Becker, or Stas, and the main developments, or the main other new things that people don't have access to are usually to master. So I guess there's a bit of a difference now. I'm not sure what if any other questions, actually, would have anything to add yourself?

Patrick Allaert 16:05

maybe something that would be quite challenging is the very recent discussion about the system that we, that we might change from. The system or the issue tracker with where we have all the bugs. I understand the current issues, I understand as well the drawbacks of what is possibly, for example GitHub issues. It might be great for some, would it be great for us? If we do it was going to be in the bring a lot of changes, and I think, 8.1 will be already slightly impacted by the change to GitHub in terms of pull request strategies, but potentially there will be another change, which is around the bugtracking system.

Derick Rethans 16:54

I have strong opinions about this, but we'll leave that for some other time. What about you, Ben?

Ben Ramsey 17:00

Right, I actually don't think that we're going to end up making a lot of changes in that regard, very, like, not in the near term, probably. But I did want to point out, or promote that I've started journaling some of these experiences, and capturing information mainly for my own purposes, but I'll be posting these publicly so that others can follow along. My blog is currently down right now.

Derick Rethans 17:28

That's because you're using Ruby isn't it?

Ben Ramsey 17:30

That's because I'm using Ruby. The short story of it is that there are some gems that were removed from the master gem repository at some point in the past, or the versions I'm using were removed, either for security reasons or what I have no idea why. And that's put, put it into a state where I just can't easily update. I just haven't, I just don't care, right now, so I plan on migrating to something else. In the short term, I'm not going to be doing that. So I've started writing at https://dev.to/ramsay and Dev.to is just a developer community website. If you're on Twitter. It's run by @thePracticalDev, I'll be, I'll be blogging there.

Derick Rethans 18:18

And I'll make sure to add a link to that in the show notes as well. Thank you for taking the time this afternoon, or morning, to talk to me about being a PHP 8.1 release managers.

Ben Ramsey 18:28

Thank you for having me on the show.

Patrick Allaert 18:30

Thank you, Derick for that podcast. I'm really glad you invited us.

Derick Rethans 18:39

Thank you for listening to this installment of PHP internals news, a podcast, dedicated to demystifying the development of the PHP language. I maintain a Patreon account for supporters of this podcast as well as the Xdebug debugging tool. You can sign up for Patreon at https://drck.me/patreon. If you have comments or suggestions, feel free to email them to derick@phpinternals.news. Thank you for listening and I'll see you next time.



235:Ugly Hot Tub PHP Coding

Links from the show:

This episode of PHPUgly was sponsored by:

Cloudways, a managed cloud hosting platform built for your PHP projects.
If you simply wish to focus on your business, Cloudways is the way to go. They take over server management and security and free up time that you can dedicate to growing your business and acquiring new clients.
The Platforms offers a choice of IaaS partners (AWS, Google Cloud, Digitalocean, Linode, and Vultr). In addition, you get a performance-optimized stack, managed backups, and staging environment where you can test your code before pushing it to live servers.
Best of all, Composer and Git come pre-installed so you can get your projects up and running quickly.
All this power, simplicity, and peace of mind falls right with their brand slogan - Moving Dreams Forward
Be sure to visit cloudways.com/en/php-hosting.php today. Sign up using the Promo code PHPUgly and get a $25 credit.

PHPUgly streams the recording of this podcast live. Typically every Thursday night around 9 PM PT. Come and join us, and subscribe to our Youtube Channel, Twitch, or Periscope. Also, be sure to check out our Patreon Page.

Twitter Account https://twitter.com/phpugly

Host:

Streams:

Powered by Restream

Patreon Page

PHPUgly Anthem by Harry Mack / Harry Mack Youtube Channel