 It takes 10 more minutes if you want to pull weeks if you want. Hi, everyone. So this is Drew. He has been heavily involved in the WordPress community since 2011, contributing to the core documentation and meta-teamed writing plugins, and helping with support. He's been a core developer since 2013 and served as a WordPress documentation lead until 2016. And he's contributed to every WordPress release since V3.3. And Drew works remotely from Arvada, Colorado for a Sandhills development, the parent company for cool plugins like Affiliate WP, easy digital downloads, restrict content pro, sugar calendar, and more. And also the last thing I did forget to tell you guys, no using any type of Wi-Fi on your phones. Use it on your computer. The Wi-Fi has been a little weird, so that's it. Thank you. So yeah, as she said, my name is Drew Janes. For those who weren't familiar with Sandhills development, these are our monsters. For all of our products, each of our products has its own monster. Laptop's freaking out. Nice. Way to start. Please hold. Anybody know where the screen isn't lining up? Did I just try turning it off and turning it back on again? Did it decide to take a little break right now? I can, while we're trying to figure out the screen, I can give you a little overview. Basically, this talk is an overview of modern PHP development. And today, I'm going to be diving a little bit more into why than how. So we're not really going to discuss, I guess, the underlying thinking behind how things work, but we're going to talk a lot about why you should be using them. There's a ton of resources online for how you can go about actually implementing things in modern PHP concepts. But I think one of the biggest things that people don't talk about is why you should be using them. So for pretty much all the concepts I'm going to talk about today, we're going to talk about the basic benefits, why each is worth pursuing. And then for almost all of them, I have sort of pseudo code examples, which are just a good way of illustrating how it works. And then in most cases, I have practical examples showing how you could take legacy code and upgrade it to use modern features, whatever those are. I guess I'll just keep going, even though I don't have slides. So let's talk about what modern PHP development actually means. In WordPress terms, that's pretty much all the features that WordPress isn't using. Because WordPress still requires a minimum version of PHP 5.2. So pretty much all modern features, that is things that were created after PHP 5.2 was end of life eight years ago. Yeah, go ahead. Or what would be considered modern features? Let me switch this. All right. I will try to rattle some off. But modern features would be considered things like namespaces, closures, exception handling, which we'll come back and throw a little asterisk on there, exception handling, type-hinting, traits, generators, all sorts of modern PHP features. In terms of type-hinting and exception handling, those were actually introduced in 5.0. And WordPress still isn't using them. Exception handling is what I would consider to be a modern PHP standard for coding, but not necessarily a modern PHP feature. And the same goes with type-hinting. Type-hinting, which we'll talk more about in a minute, more has to do with avoidable mistakes. There's actually a great tweet from Phil Sturgeon about this talking about type-hinting essentially informs you that you're trying to shove a round peg into a square hole and then throws it back at you. It's OK. I can just do it without it up there, but OK. Well, we're going to do it without slides. This is going to be fun, especially the code parts. Yeah. And by the way, I tried to upload them on the Wi-Fi, and it didn't work. So we'll do it after. Hey. My hero. No, it still isn't. It's up, though. That's a what? OK. So should I wait? Namespaces, auto-loading, closures, type-hints, late static binding. Go ahead. Traits, generators, group aliasing, and my favorite lib-sodium and modern security features. Which, by the way, we're not going to talk about today, because I could probably talk about that stuff for 40 minutes all by itself. It's not flipping over. Next. Sorry, y'all. We had this working earlier, and now it doesn't work. OK. Well, the main gist here is that modern doesn't just mean new, right? So we're talking about exception handling. We're talking about type-hinting, other things that I would think would be considered modern PHP development that aren't new is don't use globals. Use exceptions in logging, type-hinting the right smarter code. And so that leads me to a point that is follow the leader question mark. Typically, in a third-party development ecosystem, the ecosystem tends to follow the platform's lead in terms of coding style and how things are coded. And in WordPress's case, this has actually been detrimental to its development community, because while you are under no obligation to support PHP 5.2, by following WordPress course lead, a lot of plug-in developers and theme developers have not updated their code for modern standards. And so what you get is this huge swath of really, really outdated legacy code and then this sort of small little subset of people who are like, I'm going to buck the system and use modern code. But then WordPress.org doesn't support enforcing the minimum PHP versions until this year, eight years after the version that we currently support is the minimum is end-of-life. So this is not an attack on WordPress core. Obviously, the reason that the minimum has been so low for so long is that we didn't want to leave users behind. But now, this year, they are talking about actually bumping the minimum, bumping the minimum to 5.6 in April and 7.2 in November, which is pretty fast. But the upside of that is that it will allow plug-in and theme developers to update their code with core handling a lot of the messaging for users to say, look, your PHP is out of date. You don't know what PHP is. Here's an example or an explanation of what PHP is. But the main point is that WordPress core has intentionally or unintentionally held back its development community, and I'm here to help. I had this quote that I actually really subscribed to. It's from a French author named Antoine de Saint-Exupéry. He's actually the guy who wrote The Little Prince. And this quote is from a different book called Citadel that was translated into The Wisdom of the Stands. But basically, the quote is, as for the future, your task is not to foresee it, but to enable it. And I sort of view this as if you build it, he will come, kind of quote. Along the lines of, your job is not to guess every imaginable use case for your code, but to enable it by using modern standards. So let's get into some of these concepts. And we're just going to start. Obviously, you can't see it. We're just going to start with refactoring old code. Incorporating more modern PHP is inevitably going to raise concerns with refactoring considerations, too, in terms of what approach you should take. Some people take an all-or-nothing approach. They just refactor. They just rewrite their entire plugin, possibly leaving their users behind in the process. It's happened before. It'll happen again. Of course, there's backward compatibility concerns there. I'm not going to name any names, but there have been some plugins that rewrote and broke a lot of stuff. I think probably one of the more responsible routes to take is gradual iteration, where you're refactoring slowly. In easy digital downloads 3.0, we introduced the concept of partial activation. And that essentially means that if we have any less than stellarly coded add-ons that check for the Edd main class, if Edd is not active, then it's going to fatal these add-ons. So we introduced the concept of partial activation. And that is essentially where we run the main plugin class but don't run the bootstrap. And that allows these add-ons to detect Edd and still work and not fatal. But Edd itself is not active. And so if you want to see how that works, check out the release 3.0 branch on the Edd repo, which I think is still public right. That one is. The main thing with refactoring is that I want to share with you a little bit of a cautionary tale. Navigating new skills takes time. This talk sort of assumes that you have some baseline of knowledge with PHP. And just know that navigating any new skills takes time. It's not going to be instant. So you probably shouldn't jump right in with a production project. Make sure you know what you're doing before you push your code out into the world. Everybody moves at their own pace. So absolutely do dive in headfirst. Learn everything you possibly can, play around with it on your local environment. See what works, what doesn't work, what breaks compact, what doesn't. But absolutely do not jam up your users in the process. And this is a bit of a recurring theme in this talk. But the thing is, is you have to be very careful about what you introduce or don't introduce. If you're running a private plugin, you're probably doing some level of usage tracking that has information about PHP versions and all those sorts of things. It is possible to get that data from WordPress.org if you ask for it. I think Dion might kill me for saying that. But it is possible to get this data to find out how it breaks down, how your users are using PHP lower versions. You might be able to bump it. You might be surprised. We were looking at the stats for Affiliate WP last night. 30, I think we decided 66% is on 5.6 or higher. It's amazing. Like, I did not expect that. But the main thing with don't jam up your users is obviously create version protected Bootstrap files. That is files that can run in PHP 5.2 and won't break and then run your Bootstrap in a separate file. And that's just, I mean, I think that's just best practice. Don't create a plugin Bootstrap that's going to fatal the site the minute you activate it. The very least, create some kind of partial activation situation. And the number one thing I would say there is graceful fallback. So the rule, not the exception when you're refactoring. So embrace what your users can't support. That's really what it comes down to. That's the cautionary tale. We're going to get into the code that you can't see here in a minute. I'd say everyone should gather around my laptop. I don't think that's reasonable. Namespaces. I don't know if we ever figured out why it's not working. Sure would be nice if it worked, though. Yeah, we got nothing. It's not flipping over, I don't know why. Well, the same problem applies. We could try, actually hold on a second. Please hold. I'm going to see if maybe we can do a. The problem is I don't think it's even connecting. So the problem, of course, is that I can't even mirror my screen because it's not even recognizing the computers there. Problem is, do you have something that's not lightning cable? Old MacBook. It's going to have to be like a mini display or for HDMI. Sorry, y'all. Say that again. No, it's in Keynote. I have it in a PDF, but I still can't connect to the thing, so it doesn't matter. Thank you, sorry. OK, anyway, the slides will be online. We're going to talk about the basic structure of namespaces, but we're not going to be able to show code, so that's OK. That's fine. Who here is familiar with the concept of namespacing, as in 5.3 namespacing? Because even pre-5.3, there was namespacing, but it was not what we know today as namespacing. It was the adding the EDD prefix onto the front of all your functions so that you didn't collide with other code, right? The idea of namespacing in the 5.3 plus world is to create a top-level vendor, essentially, namespace, under which your code lives so that there's no collisions with other people's code. And really, the why of using namespaces? I mean, you can use your old system. You don't have to introduce namespaces. Really, the why of introducing namespaces is actually that your functions can be a little less verbose. And also, this is a big one for me. Also, it teaches you about interoperability with other people's code. Because really, namespace is the biggest benefit, in my opinion, is being able to handle dependencies without collisions. So basically, you would introduce easy digital downloads. Maybe they would choose an EDD top-level namespace. And everything under that would live under that. The other thing with namespacing, and we'll get into auto-loaders in a minute, but the other thing with namespacing is it also introduces, in conjunction with auto-loaders, it introduces some higher level of organization to a project that didn't really exist before. There wasn't really a standard for how to do it. And by the way, there's not really a standard now, either. But the difference is that it's a lot easier for you to organize your code and mimic that with your directory structure. So it's a lot easier to find things based on your directory structures based on your component namespaces. Then it's a lot easier to find the actual files that the code lived in. In the pseudocode slide, I had these ridiculous namespaces. Like, this actually works, but even though it's ridiculous. But in an actual example, it essentially takes legacy code like an easy digital downloads class and converts it to a namespace version, just so you can see how it condenses it down. And like I said, we haven't really gotten into auto-loading. But auto-loading, hey! So just know, by the way, I can't see my notes or anything. So we're going to wing it from the slides. But I don't mind namespaces. Obviously, we just talked about this, but it establishes baseline code ownership. Simple naming, code segregation, and interoperability. All right, so here's the sort of pseudocode example. My verbose plug-in class name, my plug-in class name, my plug-in component class name, my plug-in function name. You get the idea. Jury's still out on whether namespacing functions is a good idea. I love doing it, personally. This totally works even though it's ridiculous. So this is an in-practice example. In this case, we have a class, easy digital donations bootstrap extends give. And then we have a fork method that essentially replaces the word give with easy digital donations. This is a special joke for EdD fans. Give forked EdD, and we would fork give back and create a new plug-in called easy digital donations. But anyway, this is the before. We have a verbose class name that extends give, has a method, and it runs the bootstrap. This is pretty much not unlike quite a few plugins in the repo right now. But this is how we might namespace it. We might namespace it as namespace EdD, class bootstrap, extends give, same method. But when you instantiate, it's new EdD bootstrap. So it's just a lot more compressed, and it's a lot less verbose. So why use namespaces? Obviously, we talked already about naming collisions. How much time do we have, by the way? OK, 22 in. Readability organization we talked about. We'll get into it with auto loaders in a minute. With great aliasing power comes great responsibility. This is pretty verbose, but it gives you the best idea, and we'll show a code example in a minute. But the main thing here is with namespacing comes the ability to alias. So either alias in a localized form or alias in a global form. So in this case, we're aliasing legacy verbose controller class as standardized controller. Class controller extends standardized controller. And then we have the use of class alias, which actually EdD does, to fix a typo in a class name. But in practice, this is how that would look if we didn't do any aliasing. This is literally marrying new code with legacy code. New controller extends legacy verbose controller class, et cetera, et cetera. If we locally alias this, we could use legacy verbose controller class as standard controller. And this is an easy way to make legacy code much more readable if you're extending it in a new way. But the main thing to remember here is that the aliasing is localized to this file only. Whereas this version, using class alias, is actually global. So any file that loads after this class alias call runs can use the class alias. So this is a great way to essentially rename some older legacy classes to bring them into your current style. But if you remember that slide a minute ago with great aliasing power comes great responsibility, don't overuse it and don't abuse it. Don't rely on it. It's a good way to get your development community into the mindset of, this is my new style. But you should have some exit strategy for that, deprecating it, moving the code, all those sorts of things. This is a good sort of middle step approach. So yeah, auto loading, what you need when you need it. The main thing that an auto loader does is remove the need to load your files before you call them. It sounds kind of dumb, but when you have hundreds of classes, I'm pretty sure we've all seen those plugins that have these massive blocks of require statements, requiring all of the things. It typically follows a project organization which we're actually not going to get too far into. And your standard auto loaders would be Composer, PSR0-based, PSR4-based, or rolling your own. The thing with the PSRs is that in most cases, if you're following court courting standards, it's not going to work very well for you. The main thing is that the way auto loaders work is that they convert class names into files, file names. And so that, of course, means that your namespacing has to follow your file structure. And then it basically has to be guessable based on the name of the class. This is a very, very, very, very simple auto loader. It takes a class name, and it looks in a directory called classes for a class with a file with that name, class.php. Like I said, we're not actually going to get too far in auto loaders, because I could talk about auto loaders for quite some time. But here are some resources. And again, these slides will be online after the talk. Tom McFarland's auto loader there on the bottom, simple auto loader for WordPress. My auto loader that's linked right above it is actually a fork of his. And I use it in a couple of my projects now. And the reason it's a fork of his is that I added support for interfaces and traits. So type hinting. Hinting at mistakes before you make them. I love this tweet from Phil Sturge, and this is actually from last week. Types aren't docs. Types aren't tests. Types aren't a Cocker Spaniel. Types aren't a Fine Age cheese. Types are good at letting devs know they're shoving a round peg in a square hole. And that's great. Use them appropriately, but also write tests and write docs. The main thing with type hints is that obviously they help catch avoidable mistakes. And it defines expectations. Prior to 5.1, base support was added for class and interface names and or self. 5.1 added array types. 5.4 added callables. 7 added scaler type support, which was huge. String, bool, int, float. And you're not allowed to use aliases, by the way. 7.1 added iterable, 7.2 added object. So let's look a little bit at what that looks like. Basically, type hinting is very simply in line documenting what type a parameter can accept. In this case, obviously, we're passing collection, collection, array, attributes, et cetera. And we're going to actually talk more about the try-catch later. But in this case, it's setting a type against the exception. And we'll talk briefly about why setting the type there is important. So this is an example, sort of a boiled down example of what's in EDD 3.0 coming soon. We essentially created what's called a marker interface in the EDD exception interface. And the way that works is you create a top level interface that all of your exceptions implement. And so what that means is that when you're anywhere in your code, you can catch all exceptions that implement that marker interface, meaning that all of the EDD interfaces implement the EDD exception interface, and therefore we can catch any EDD exceptions that get thrown. We actually use a different function, but I just wanted it to be clear. So here we're error logging the code plus the message. Maybe something that's a little bit more familiar. Here I've converted two core function signatures to add type inting. And by the way, it was quite difficult to find two core functions that only accept parameters that accept only one type. WP insert posts. We added the array type int in the Boolean WP transition post status. We had the string, string, and WP posts. For method examples, like a class constructor, we added a collection type for a collection parameter. And the last one's kind of a bonus. It's what's called a return type declaration. And that is essentially a case where you're declaring that this is the return type of this method, whatever that is. A bad habit that's sort of festered in the WordPress PHP community for a long time is multiple return types from different methods. If it failed, return false. If it didn't, then return something completely different. Modern best practice would be to try to return the same type from everything. So let's talk a little bit about nice to haves. Avoid running over your users in pursuit of shiny things. This goes back to that argument about what we talked about earlier, some plugins refactoring maybe a little too quickly, breaking back compact, leaving users behind on purpose. I mean, sometimes you have to rip the bandaid off, but be careful about ripping off the bandaid with your entire user base. So nice to haves. Closures. I actually consider closures to be a nice to have and not something you should necessarily be using a lot of. Closures are essentially anonymous functions. But obviously, before 5.3, there were the concept of anonymous functions. You could create function. But the main thing is that it's a really simple way to express simple one-time use code is the best way. But the main thing is that you should be careful using closures with hooks. And that is because the closure instance is not globally accessible. Which means if you hook to a WordPress hook with a closure, it is unhookable. Unhookable, I guess is a double negative. If you hook to a WordPress hook with a closure, other people cannot unhook it, unhook your callback, unless you make it globally accessible. So in most cases, I would say don't do that. In very, very limited cases, I would say use a closure in your core plugin to hook something to one of your hooks that you absolutely do not want anyone to unhook. But use it sparingly. This is a common example of having a callable parameter in a function. FeedPet was a callable message. You call FeedPet, you define your closure that echoes my pet has been fed. And then finally, probably one of the most common uses of callables in WordPress, I would say, is in the realm of display callbacks. Obviously, in most cases, you're not using closure, but all the same. So this is an example from Edd 3.0's reports API that's coming pretty soon. The main thing here that's happening is you can define a display callback when you instantiate an endpoint. So in this case, we're defining the display callback for this endpoint on the fly. If you look at line 11 and below, we're defining the display callback as a closure that gets past the endpoint object. And then we're echoing the data or whatever. And then if we call the display method for the endpoint, it performs that display callback. So this is a pretty good example of on the fly. This is another area where closures are actually as callbacks for sorting methods and sanitization things. A lot of times, you'll see something like ArrayMap absent and then an array of IDs. That's basically this. We're just defining a closure to do it on the fly. Same thing with the sorting method. So yeah, closures are handy, but be careful how you use them. Who in here has ever used late static binding in a project? Late static binding is a concept that throws object-oriented programming on its head because it essentially allows the parent class to statically access things and extending subclasses. So probably this is the easiest way to explain this. We have class alpha, class beta, and class beta that extends class alpha. Both define static methods, but in this case, if you were to call new beta get class name, you would get alpha. And that's because on line seven in get class name, we're calling return self get name. Because of inheritance in PHP, self is specifically to the class it's being called in. So in this case, self refers to alpha. So even if you call it from an extending class, it's always going to think self equals alpha. So if you change that keyword from self to static, that essentially allows the parent class to call a subclass method. So if you were to now call beta get class name, you would get beta. So traits, this is honestly one of my favorite things. And I think it's wildly underused. This is a simple concept. Wheel extends wheels. Engine extends engines. This is actually a fairly common problem. In this case, both classes are extending different superclasses. And in this case, they're actually both running code that does the same thing. But because they're not extending the same superclass, you can't abstract that up. So essentially what you end up with is two classes using the same code. Well, see here in red. That's the duplicated code. If we were to create a trait, this is PHP 5.4 plus. If we were to create a trait that holds that code in these other classes, Wheel and Engine, we could just declare that we're using this trait. And that automatically brings that code in. So then the constructors can use this set mechanic from the trait. Obviously, in this case, it's basically the same number of lines of code. But ultimately, it means you could reuse that for any number of components. I'm going to skip the group aliasing thing, even though it's really cool, because I only have a couple minutes. But the main thing I want to talk about is back in Compat to look out for. This is obviously using modern PHP. Call time pass by reference is a big one, because it fadles in 5.4 later. That is essentially passing a parameter by reference when you're using a function. Don't do it, because it'll fade out your stuff. PHP 4-style constructors, I don't know if anyone here's even written PHP 4-style constructors before. But it essentially, in class constructors, the way it works is you had a class named whatever. And then if you had a method with the same name as the class, it would be treated as the constructor. And WordPress Core actually had PHP 4-style constructors for a while. But at a certain point, they were deprecated in 7.0. Static calls and non-static methods were deprecated in 7.0. A closing with a quote, software is a great combination between artistry and engineering from Bill Gates. The only cautionary note that I would put with this quote is, don't forget to be an engineer, even if you're being an artist. Even if you're suddenly exploring and discovering all the new, wonderful features of PHP, don't forget that you're an engineer. And don't forget to be careful what you wish for. Thank you. I think there's only like a minute left. How much time do I have? Two minutes for questions. I will also be here all weekend, and I'll be at the contributor van Sunday. Anybody have any questions? I don't have enough time to get into Composer. He asked about including Composer and preventing collisions with other projects using Composer. I don't think I have enough time to, but we can talk about it after if you want. Anybody else have any questions? That URL that's up there, that'll be good in a minute when I upload them. Yeah. Well, the first one I don't think has a name. The second one, I have no idea because it's for WP SimplePay, which we just recently brought into our portfolio. This is Ed for EddD, does the whatever that is have a name. For Sugar Calendar, Gia. Gia is the whatever that is. And the ELF for Affiliate WP and RACS for RCP. Sure. Gia, I'll have to remember that. Sorry, JTRIB. Anybody else? Thanks for bearing with me on the weird slide problems. Thank you, everybody.