This presentation is brought to you by RingCentral developers. Revolutionize the way your business communicates with RingCentral's API for voice, SMS team messaging meetings and facts. Don't just be a developer. Be a game changer with RingCentral developers service. So we're going to talk about the dark corners of the SPL. First a just a real quick self introduction. I'm Omni. I currently am a full stack developer at when I work up in Minneapolis, but y'all didn't come to hear about me, so let's go ahead and get started into the SPL. So quick overview of the SPL standard PHP library is a set of things that can be used to simplify or standardize the PHP code that you write, as well as a few things that might be able to speed up your code or maybe improve memory usage in a few specific situations. Over this next almost hour, we're going to talk about some of the builtin data structures along with a few contrived usage examples. We're going to talk a little bit about some of the interfaces and classes that you can extend along with why you might want to. And we'll very briefly talk about some of the iterators and exceptions. I'm going to very briefly mention them only because there's already a lot of other talks out there that you can probably find. They go into into them in depth.
So starting with installation back in the olden days, we used to have to install things the hard way. PHP five actually made this part of the library compiled by default and available for you to include simply by changing a pH BI and I setting as a five three, it was moved from being an extension to being built into PHP. So you don't actually need to install anything through composer or Pechal if any of you remember the dark days of Pechal and in theory, since these things are built in C instead of user land PHP, hopefully they've got some nice performance characteristics. And I'm going to talk quite a bit about some of those. So the meat of this talk is about the built in data structures that a lot of people are unfamiliar with. I'm going to go into them as if you do not have a computer science degree or as SIF.
It's been a while since you since you went all computer sciency. Again, most of these data structures could be written in user land, PHP since they're built into the language in C, the might be inherently faster, although again, we're going to do performance testing to show whether or not that's the case. We are going to talk briefly about each one of these algorithm or data structures performance characteristics using the big O notation. A, I'm going to assume again that you have been in the industry for awhile and have forgotten it since we don't use it very often in the real world. It's a computer science concept about the worst case scenario for an algorithm or a data structure, either in terms of execution, time, memory or possibly both. So things at the top of this list in general perform better than those lower down.
However, since most of these things are based on the concept ofN , which is the size of your dataset it also means that for very small datasets, these, the difference between some of these is, is much smaller. So if you're not dealing with a large sets of data, a lot of this is purely academic. However, that being said, most of us realize that if your software is successful, eventually your dataset grows pretty rapidly. And this could get you into trouble if you choose a poor algorithm or a data structure. So here's a quick graphical representation of the different complexities. So things lower on this graph are generally much better than those that are higher. We're briefly going to touch on the big O for each data structure so you kind of know what to expect with it and what each of them excels at. So for my performance testing since that was kind of what got me into this whole talk I created a simple array version of each of these data structures with 1 million elements and then I either sorta did or tried to test it in whatever, whatever operations made sense for that data type. Again, as with all performance statistics or statistics in general, take them with a huge grain of salt. A Texas sized grain of salt would probably be best and test them yourself.
So let's get started with the top of the list. The w link list has, and it's two children classes, the stack and the queue. So assuming you've never done a whole lot of computer sciency stuff, a w link list may be unfamiliar. It is a data structure where you have two nodes or a node with with two different links pointing to the previous and the next node in the list so that you can kind of iterate in either direction. And then you also have links to the beginning and the end, which we tend to call the head and the tail. This particular example shows integers as the data type, but that's not necessary. You can store pretty much anything you want in there. Performance on this list is pretty flat. Anytime you want to go across the list, whether you're trying to find a particular node or a particular value in there or access accessing a particular one it's big O is in. So the larger dataset it's going to grow linearly as you have to go across it. However, adding or deleting
Takes constant time. Though, again, if it's in the middle of the list, you have to find where you're adding or deleting to basically to add, you just create a new node point the next and the previous ones to the appropriate nodes and then move the links from the next and previous notes to point to the new node you're adding. And similarly, bleeding is basically the same. So those operations are constant time. The nice thing about this is because we have links to the head and tail nodes, if we're going to insert or delete from the head or tail, we don't need to search. So it's basically constant time. It doesn't matter how big your data set is to add or remove from there. This makes it really good for things where that's exactly how you use it, such as a stack or a queue.
And again, we'll get into exactly what that means in a second. But now we're going to start with a contrived example. So say you're building a game that has con combat of some kind and you need to track what order the characters can go in. Characters can become incapacitated or and need to be removed. Other characters may join in the fight and need to be added. So for the sake of argument, in this particular example, all of our characters have rolled dice somewhere else and we're going to stick them into our list in descending order of their initiative. Luckily for us, they happen to roll initiative in alphabetical order so that it's easier to remember what order they should go in. So now we've got a list with four people in it. We can iterate over it like we might any other kind of array or data structure with four each.
And you'll see something like this pretty boring, nothing exciting. But let's say a new character joins the fight and needs to take their term before eco takes theirs. So to do that with a normal PHP array would take a little bit of effort. It's not, it's not immediately intuitive how to add in the middle of a array. You could splice it and rejoin things. You can, you could move things down, you could resort things. Again, it's not difficult, but it's not as easy as simply knowing where you're going to add it and calling list add. So in this case we're going to add them to the third spot. And now if we traverse the list again, you can see that Delta is going to go before echo.
So let's start the battle. We're going to rewind and we've picked somebody out to go first. The first person gets to go the list arrow current and they've picked somebody to do attack. They're going to attack the second person. Their attack is super effective and that person needs to be removed. So now we call list offset unset and that person has been removed. Sorry Katie. Not a good time for lap. So if we iterate over it after taking out Charlie, you can see that they are no longer in it. Again, all of this is totally possible using associative arrays. This is a contrived example just to show how it might work and to lay the groundwork for some later examples that will make a lot better use of whatever data structure we're looking at.
Now the nice thing about this class again is that we have links to the head and the tail. So we can do things like build a stack or a queue from it. I'm going to basically go randomly between actually saying SPL before these things and not saying SBL before them. It is a goes before all of the data structures, but when we're talking about them, it's hard to remember to do it every time. I don't know. I apologize for that. So the SBL stack is a life O structure, which is a last in, first out. Basically. You can think of it as kind of a pile of books where you pile them up from your table and you can pull off the top, you can put a new one down, you can put another one down when you pull it off, whichever one you sit down. Last is the first one to come off. Cue on the other hand is more as a FIFO structure, which is first in, first out. It's kind of like a line in the grocery store. You join at the end of the line and people there first go before you. The Q does adds the methods to the class that lets you think of it more like a Q, a namely inQ and DQ. But the underlying code is basically the same.
So here's the gist of how the performance stuff goes. We're going to grab the starting time and memory size at the beginning and then in the middle, in this case, we've got a stack made out of a typical PHP array versus one using the SPL stack. We load both of them with 1 million random numbers, then pop the elements out and write them to the screen.
Unfortunately, in this example, the SPL stack is actually slower and bigger than the simple array implementation. You'll need to decide which one looks better to you based on what your team thinks. If you're building a stack using an array, it's not intuitively obvious just looking at it that that's what you're trying to do. So you do have the array operations array pop array, push array unshift or shift that can mimic this sort of thing. And then of course the SPL queue works very similarly with almost identical performance characteristics. I didn't feel like it needed to be shown again.
Next up is the heap. A heap is a tree-like data structure that has either the greatest or the least value at the top of the heap. Again, depending the type of the heap. So a men heap has the smallest value at the top, a maxi pads, the greatest value, and within the heap, each child node of the root node is also a valid heat and it goes all the way down the stack. So that is kind of hard to explain. It's much easier to understand what the visual representation, so this is a max heap, not necessarily an SPL maxi, but it is a map max heap and you could see that the root node is in fact the greatest in the tree and that each of its sub trees also has the property of being a max heat. So no matter what order you insert into a max heat, the root note is always going to be the greatest or at least equal to the greatest. So you can have duplicates in there. Now the problem is basically anything, I guess not really a problem. The performance characteristic of this is anytime you try to do anything with it, it requires you to touch basically half of the paths through it. Whether you're adding something, removing something, searching through it or whatever. Basically it will add it to a node the root node and then reshuffle the tree to make sure that everything works or other implementations might add it to the bottom and then reshuffle it so that it's everything is still in maxi.
So let's start, let's do another example. We're going to create a class for each character rather than just going by name. This could easily be an associative array or just a standard class. This is just a simple class storing the characters name and their initiative. Pretty simple. Then we need to implement the SBL max heap with a comparison method. In this case, we need the compare method to return greater than zero. If the first character's initiative is higher than the second zero, if they're equal or negative, if the second is higher, if you've ever used any of the user sort functions in PHP, the concept is exactly the same. You probably have written something almost identical for this for user sort. But it works the same. And obviously if you made a reverse the logic on that, then you could make gay men heap using the same concept.
So then we're going to put our characters and some random initiatives in and we can iterate over it like we would any array. And you'll see that they are in fact in a descending order of initiative
Traversing the heap in this way does leave you with an empty it because of how heaps work. Basically it pulls the one off the top and then reshuffles the array so that everything is still a max heap. If a character however were to join the battle halfway through, we could add them the same way we added the others and they would automatically be put into the right place. Now clearly you can store more complex data and you can sort it however you want. So if you have a, instead of just having an initiative value for a character, if you had a bunch of attributes and their initiative score is based on maybe a random number plus some initiatives, this could easily handle that.
No, an implementation, a strangely a heap as much slower than my test implementation for this test case. But it does take half the memory. I will say that this timing is a bit deceptive though. This example does a lot of inserts all at once and then iterates over it, which is not really what he excels at. If you're adding things while you're pulling things out not necessarily at the same time, not necessarily in any sort of order. A heap would really shine where you pull something off. Maybe you put two mourn in, you need the next grade as you pull it off, then you need another one. You pull it off, then you need put two more things in there that may or may not be the top one. That's, that's really nice. That's what it really shines doing. As opposed to if you were to build the same thing using an array, you would have to put it in there, sorta put something else in there sorted so that things are always in the correct order. Now speaking of PHP res, I'm going to temporarily skip over the SPL object storage in this list. We'll get much more in depth into it and a little bit.
[Inaudible] Excuse me. So PHP arrays are in the ones we normally deal with are actually associate of arrays implemented as hash tables. This allows us to use things like integers or strings as indices. We are not required to have continuous keys. We can easily resize it on the fly without a huge performance performance hit. The SBL fixed array has a bunch of constraints that make it less flexible.
Oh, you can think of it as an old school array where we tell what size it needs to be at the beginning. And it can only store that much data. The only indices you can use are integers and they must be continuous.
It does have some pretty standard array style performance characteristics in that if you know exactly where you're looking for it's constant time. If you are searching, you have to assume you start at the beginning and go all the way to the end. So your search is a big [inaudible] and depending on whether you're inserting into an RV existing in DC or if you have to resize the array your insert could either be constant time or we have to make a copy of the array copied over. So you end up with a insert time of big O of N. And similarly, if we're going to resize it smaller delete is a constant event or a runtime event. However, if you're just knowing a thing in there, you already know about that is going to be a constant time as well. So here's a couple of PHB rays because they can have different kinds of keys and can store any kind of data. They're very flexible. Unfortunately in computer science, and in fact, most of the world flexibility almost always comes at a performance or memory costs. So the data is stored the same whether you're using a diverse set of keys or a continuous block of integers and whether you need to resize it or not.
A fixed array is used pretty similarly to a normal PHP array. It is in fact an object, so you can't initialize it using the Reiki word or the bracket syntax that we've all come to know and loved since it was introduced. If you tried to go past the end of a fixed array, you do get a warning or excuse me, an exception. It is a typical exception. You can catch it. You can catch it and then resize the array if you want. But again, resizing is not a trivial operation so it shouldn't be taken lightly. If you are going to be resizing your arrays quite a bit, it may be better to just go ahead and use a standard PHP array. That being said, here's an example of using set size to increase it. So we add a bunch of things. We then realize we need to add one more. We set the size to four at our new one and you can see it fits it there.
Now you can also convert tune from standard PHP arrays and you can iterate across them like normal, which is pretty nice. If you're dealing with huge datasets, the fixed array might be worth looking into. So as far as performance goes, putting 1 million elements into a fixed array, it is slightly slower on my machine. But it does take half the memory, which is pretty cool. This is actually where I got the idea to do this talk. I was having to crunch a whole lot of numerical data that I didn't care what order it was in. I just needed to store a whole bunch of it at once so that I could do some aggregate operations across it. And I kept burning out of memory. I could obviously reset things in my pH BI and I to increase it. But it turns out that just using a better data structure kept me from having to do that
Again. This is not going to be useful for all of your use cases, but if you have to store a ton of data and you don't care about the keys, this might be perfect for you. So I'm going to skip over the priority queue. It is very similar to the way heaps work, whether it min or max, except you're not sorting on the actual value, you're sorting you pass in whatever you're trying to store and then you also pass in a priority. And the priority that you pass in is what it would sort on. So in our earlier example, instead of passing in a character and then part of that character was their initiative score that we sort on, you would pass in a character and then an initiative and it would sort on that this, these are actually useful for things like cues in the form of like rabbit, MQ those sorts of task brokers where you have put things into the queue and eventually they'll get to them. Some of them also have the concept of a high priority task where it jumps to the bottom of priority queue, lets you do that, which gets us to the SPL object storage.
This is a very interesting structure. Most of us have not used it that often because it's kind of a particular use case. But basically it boils down to you wanting to use an object as a key in an erase so that you can store information about that object as a value in the array. So that's kind of confusing. But let's, let's get into it. So the concept looks kind of like this where you've got an object we're trying to use as a key and we want to store something else about it. In this particular, again, contrived example, we want to store some ephemeral data about the character object. That data may be very transient. Say in a case of a role playing game battle we might store whether they, they're alive or dead and after the battle information gets tossed out. If you try to do it with a normal PHP array, you get a legal offset type warning, which is kind of a bummer. So let's go back to our combat scenario as an example. So again, let's say we're building a Japanese style role playing game, or as the Japanese call them role playing games. You've got a bunch of characters and maybe some enemy objects that are fighting. Each of them can have various status ailments or buffs applied to them. That changed the way the battle works and are only valid during the actual encounter. Here. We're going to create some characters and some bad guys for them to fight
Along with some metadata about them. Each character is going to have a, an array of things that can attack work on them. So buffs like haste a poison, maybe they're floating maybe they've got something else, maybe they boosted strength, whatever it is, we can store those in them.
So when we create our object storage, we then instead of just inserting them, we actually what's called attach it to it. This allows you to only have one of each instance. And then we also pass in a whatever we're trying to attach to it. So in this case, we're inserting say a fighter and we're attaching an array which has a haste boost, may has haste and has already been poisoned and so on. So if you try to iterate across it like you normally would, you get some really weird things going on. So because of the way object storage works, the value in there is actually what you're looking for. So under the hood, this is what it looks like. So one of the nice concepts, so they SBL object storage is you can't insert the same object as a key twice, just like you can't have two keys in a normal PHP array that have the value. One, you can't have two objects in an SBL object storage that have the same, that uses the same object
So underneath it's storing it by its hash. I don't exactly know what a hash algorithm it uses. So I don't know about hash collisions but it stores it by that. Then we then it attaches to elements of data about it. OBJ, which I am going to say means object and inf which I am guessing means information, which is whatever information you store about the object. So if we iterate over it again, but we call the value the key, it makes a little bit more sense. So you would get the key, we can print that out and then a D reference it by that and you can see that's more of what we were expecting. So the first line key, we have a character object for the fighter and then we have that array of things that we stored about it. Normally I ask four questions. Since y'all are in the same room, I'm going to assume there's no questions. We can definitely get into that later. I'm going to take a big drink of water away from the Mike though.
The SPL interface or defines six interfaces as well that you can use. I imagine most people have probably be an introduced to countable if you've built any custom iterators that you may have used some of the iterator interfaces. And if you've ever implemented the observer design pattern, you probably have used the SPL observer and SPL subject. I'm going to skip over the iterator in a few cases. There are plenty of great talks enter King games based around doing talks about iterators. This is basically lunchtime in the middle of the day for us here in the United States. And I don't want everyone to be too hammered to either continue working or get back home safely. So I will not say the I word again, but I will quickly talk about how to implement some of these if you choose to. So the countable interface is a super simple interface that lets you just run, count on something. Any class that implements this interface can be counted using the count a function in PHP. So we built the class, we implement the function and we can then counter class, right? Oh, like we didn't do it right. We forgot to use the implements keyword. Even if you implement everything that an interface requires, if you don't use the, the implements modifier on the class, it will not count. So we simply say implements countable and now it works. So the observer pattern is a
Pretty common data pattern where you have something that needs to be observed by observers. We call it the subject. And whenever something changes on that subject, we want to notify the observers that something has changed. And this requires two interfaces that work together. The first one for the subject, whatever is making is being changed and is notifying other people. It has three methods that you must implement, attach for an observer to say they want to observe the subject, detach for an observer to say they no longer care about the subject. And finally notify which has the subject call the update method on each of the observers. Obviously these are tightly coupled. So that brings us to the observer interface. SPL observer defines an update method, which simply takes the SPL subject that's going to notify it. If something
That is kind of hard to explain, not in today. If, let's build another example. So first we have the basics of a character class. You might recognize some of this from earlier. We're going to give each character a name and they'll have a message that they can send and they'll have an SBL object storage. They can store their observers in. Obviously we've already gone over the SPL object storage. This is one of the better uses of it that I've seen is using it with ya spiel observer and subject. And we'll show exactly how that works in a sec.
But then we have the three methods required to fully fulfill the SPL subject interface you need, attach, detach and notify that led observers well observe the subject. So it's interesting that the SBL observe or SPL subject requires attach and detach, which are basically the same method names used in the SBL object storage. It's almost like these were built to work together. So we implement, attach and detach. And then we have notified which simply goes through the observers and calls the update method on each of them sending the subject. So then we have our update method, which is required to fully implement the SPL observer interface. Basically it lets say subject form this observer that something has changed and that the observer would didn't need to see what it is.
We have a method for the character to accept a message to send as well as one for observers to read the message.
And finally we're going to attack, set up a bunch of characters. We're going to attach a bunch of them to each other. So they're all observing each other
For the fifth. Doesn't pay attention anyone cause he's kind of a jerk. Then we have a conversation between these characters. So when we run this, we'll see something like the following. So you can see the fighter receives a message from Paladin major received the same one the fighter sentence or that major says something the fighter. Then Leroy Jenkins into the battle. If says something, everyone else has been listening to thief. So they get the message but no one hears anything from the fif cause he's a jerk. So using this you can build kind of a publish subscription or pubsub type concepts. Basically anytime you need something like a message bus, you can build it using the observer pattern.
Yes, bill also adds a bunch of exceptions that you can use. Most projects will define their own exceptions that mimic some of these like out of range exception or invalid argument exception. The SBL also provides these standard ones so that you don't have to, clearly it's up to your team to decide whether you want to use these or custom ones or some combination of which you may want to extend some of these so that you've got your own exception hierarchy. One of the things that I don't like about the SPL exceptions is it doesn't really explain what some of these are for. For instance, what is a domain exception? Does that mean we can't find the DNS record? Does that mean the whatever we're interacting with is not appropriate for whatever domain of knowledge we're talking about? It's not intuitively obvious.
Some of the other ones have kind of been fixed by adding a strong typing. For instance, the invalid argument exception I've used to use that to enforce type safety in my own code. I'm expecting an integer. I check to see if it's an integer. If it is not an integer, then I throw an invalid argument exception. Length exceptions can be used for things like whether you are trying to go past the T array or I'm expecting an array of two values. You gave me three a that is a length exception. Similarly, if I know that my array is three elements long and you try to access the fourth, I might throw an out of bounds exception. And so on. The one I use most often in this is the runtime exception just because that's stuff that I know can happen, but it's not something that should happen. But as part of the normal program flow, if that makes sense.
This feel also kind of semi randomly adds a few new classes for interacting with files. These are very high level interfaces for interacting with files in an object oriented way and allow you to get down to some details like last modified time or to read and write to an object using object picked oriented methods instead of those core PHP functions that have been there forever. Like F right? So if everything else in your code is object oriented, it might make sense just for the sake of consistency. Teach you some of these they do add a few things to make it a little bit simpler. But again, that's, it's really up to, to you. It is good to know that they exist though in case you ever see them.
Finally, there's a re object which is quite useful. Basically it allows you to treat your class as an array. Never really came up with a compelling example with my characters. But it's basically used to make, if you need to make a class that quacks like an array this is kind of the duck you're looking for. So say my battle earlier, I needed, instead of using any of those other data structures that we used we needed something that just simply stored them in an array. But we were using a class for it. You could use array object to make that happen.
And with that being said, that is the dark parts of the SPL. Are there any questions all of the different methods that you shared with the SPL what would you say are the most useful? Are the ones that you use the most of the methods? So I've had most experience, like the one I've used the most, that I found the best for just my particular use case was the the fixed array just because of the amount of data that I was working with. But the observer pattern in some of my other, my personal projects have been a real lifesaver for just getting it done and not having to think about the logic of how it should work. But the publish, subscribe idea is not something that is particularly relevant to a lot of the software that we write.
Okay. another quick question for you here. Outside of like the, the memory and the time usage that you mentioned with some of them, are there other gotchas that you need to be worried about with some of these items in the SPL? I wouldn't say gotchas. I feel like despite the, some of the I guess bad performance characteristics of some of these, the not using them I feel is actually kind of a gotcha. Because if you, if you just see a bunch of operations on an array, it's not immediately obvious what you're trying to do with that array. If, if like most of the time when we use array, we just put a bunch of data in there and then we iterate across it. But if you're doing any of the you know, whether or sorting some of this stuff or trying to keep things in order or add things to the beginning and, and it's not immediately obvious that you're, you're treating that array like a stack or a queue where if you actually call it a stack or a queue and use a class for it, anyone who is familiar with the concept of stacks and cues immediately know how that data structure is going to work.
So what you can do all of this stuff with PHB arrays, which let me be perfectly clear. PHB arrays are one of the best things about PHP. They're super powerful. They're super awesome, they're super flexible. Going to other languages which have much more constrained concepts of arrays is sometimes annoying. In a lot of those cases, it also lets you know just how much you can shoot yourself in the foot with using PHB arrays, storing random data types and whatnot. Which is one of the nice things about when you implement the ACU for example. If that queue is always expecting integers until we get a typed raise, which I think is coming up in the next version of BHP. You can, instead of trying to force an array to only contain integers and using it like a queue, you can implement a queue where you have when you call the enqueue method, you can set the type on there.
So while the performance may not be perfect for you I feel like doing something that immediately signals your intention to other coders is, is definitely a great feature of some of these, especially when you consider that those other coders might be you in two weeks. Cause I know I don't remember what I wrote two weeks ago and looking at him like what idiot wrote this for the record? I have never ever done that. I feel like you might be lying to us. I'll plead the fifth for two more quick questions. You got Tanya's attention with the the game examples. So I'm supposed to ask, do you play a world of Warcraft? I do not. I tend not to get sucked into massive or massive multiplayer online, whatever. I don't really like people that much. So, so I have, I have not I tend to go with the ones where I can play by myself in my own free time, whatever that means.
I'm really into final fantasy and I love all of the final fantasy games that I played except for 14, because that's an MMO RPG. Nice. But you're getting Farber than me. When, when Tanya first asked me about M RPGs that was called, I was like a deer in headlights. Her responses. Yes, you are awesome. And I'm kind of telling you off from asking more questions, otherwise this will become a video game talk. The last question I have for you, Omni and again a huge thank you for grid presentation. Are there other resources you recommend for Boohoo who want to learn more about a SPL or dig more into the different methods that you mentioned? So most of the information I gathered actually came from the PHP manual which is fantastic. I, I don't, I don't know how many other languages people have dealt with, but dealing with the PHP manual is always one of the nicest things about PHP cause it's so well done.
So kudos to whoever wrote most of that stuff. As far as other resources looking at, you know, if you're, if you're going to implement the SBL max heap for example looking up what exactly a heap is in, say like a, a computer science textbook or something like that will give you a lot better insight into why you might want to use it. I don't think the manual does a great job of explaining some of that. You know, the, I think a lot of these were introduced in the classic gang of four design pattern book which I read like 20 years ago. So I may be completely wrong about that. But that's where things like the observer pattern and stuff like that really took hold for me.
Awesome. And I completely lied to you. We just have one more question come in. And it's actually a statement of question. I didn't even know that the observer stuff it really, or I really liked the SBL and all the things it provides. But with that said, why do you think it isn't more popular? And pretty much every framework has a custom implementation for most of those methods.
That is a great question. So when the SBL was first written, I, I think a lot of the performance characteristics that I brought up were, were much more tilted in it's favorite because it was, it was written in a very clean way. And once they moved into core and was written in C, it was inherently faster than anything you could write in user land. Unfortunately PHP seven has made user land code so much faster that I think a lot of the performance gains that you could get by moving it to see, just, just went away. The, the compiler has gotten so much faster, so much better that a lot of those things just don't make sense. But I think basically it boils down to a lot of people didn't know any of this stuff existed. I definitely didn't. Before I was trying to figure out how to shove a whole lot of data in there.
And I found out about the the fixed res other than that, part of the problem is we are software developers. We like writing software. Most of us when we get done with work think about writing maybe a side project or doing some open source work. We like writing code. So rather than used a, a cue that someone else wrote, why would we not just write our own it could then be perfectly tailored to our individual use case rather than kind of pulling something off the shelf and using what someone else has written. And I think, I think a lot of us you know, our own, our own arrogance keeps us from using other people's code though clearly with the rise of open source software, that's becoming a little bit, well I guess a lot less of an excuse.
I have also never written code and recreate the wheel. Yeah. I don't feel like we get called out for saying that so many times. Now I'm here again. Thank you for a tremendous presentation. Thank you for sharing a lot of information about the standard PHP library and going to the dark corners of it and for taking time to, to address the questions we had as well. Again, great presentation. Really, really appreciate it being on here today.