At camp. And thanks for coming to tighten up your tighten up your Drupal code using PHPStan. My name is Matt Glaman. I'm the maintainer of PHPStan Drupal and I'll be talking to explain what is PHPStan and the extension PHPStan Drupal. So PHPStan stands for PHP Static Analysis Tool. Um, it finds bugs in your code before your users do. Is PHP is a scripting language. It's not compiled like go or C. So once the web server runs your PHP code, it gets compiled and executed. And that's when the bugs appear. Not while you're writing your code necessarily. And using static analysis with PHP stain, it can help find those bugs ahead of time for you. PHPStan. Drupal is an extension for PHPStan, hence the name that allows it to read and understand Drupal code a little bit better and more easily. And you may be familiar with some other tools if you haven't used PHPStan yet. So first, let's walk through the different tools that are available and why they may not be the best fit. So there is this line of code here.
I tried to make it as big as possible and you can see here is hook node insert. And it says if node is published but there's a typo in published or missing the s. So how can we use these tools to find that we have a bug in our code with a undefined method, which would crash the website because it doesn't exist? Linting. So PHP actually has a built in linter. You can do PHP dash l to lint PHP code for syntax. Great. But this isn't a syntax error. This is a um, this is just a typo. And as far as PHP is concerned, this is all valid syntax, so it would not catch our bug. PHP code sniffer PHP code sniffer will take your code and tokenize it, and it'll kind of parse through it and put certain rules in place, which is great for um, it is great for enforcing coding standards, but not necessarily catching bugs, annoying the entire context of the code. Okay. There is also fan um, which was created by Etsy and uses the the AST extension for PHP, which AST stands for Abstract Syntax Tree. And then there's also Som, which was built by Vimeo.
And these are two different static analysis tools that are for PHP. But they didn't really have a great way of working with Drupal or getting getting it to understand drupal's auto loading. So it's very difficult to integrate with maybe since time has gone on, maybe a little bit. Ah, then maybe they are easier now. But it wasn't at the time. And then PHPStan PHPStan made it really easy to write an extension that could hook in and make the static analysis tool aware of how Drupal does its dynamic auto loading. You know, we can turn modules on and off. They're not automatically just defined via Composer, and it also uses the PHP parser library. So it doesn't need an extension. It uses a PHP library that will take PHP code and turn it into an abstract syntax tree for processing. Um, it allows verifying calls to classes and their names, like does a class exist? Does the method exist on the class? It verifies different types that are passed in. You know, it could argue like it'll catch like, hey, is public.
You got a typo here. That method doesn't exist. So it would throw an error. Or what if that method actually returned a string? PHPStan could say, hey, you're doing an if statement against a string that's not a boolean like you have. You have invalid logic. And that's the benefit of using PHP standard static analysis, because it can help you tighten up your code, reduce bugs before you even ship it out to customers in production. So what can PHPStan do for you? There's different rules for PHPStan, and this is a long list. It's horrible for a slide, but the idea is that there's level zero, which is can I run PHPStan without it crashing? There are some code bases where it could crash. Drupal did that. Drupal core did that at first. And then there's level nine, which is like as strict as it can be. And that's where you can't use mixed types, where it could be like anything. So there's varying levels. I recommend that you always go to level two because at least that level two you will find undefined variables and it checks unknown methods on objects.
It's like if you want to cover your bases, use level two. Personally I would say like aim for like level six because that's when you get a lot more of the like dead code checks and other goodies in there. Drupal core is running at PHPStan level one, so every bit of code that goes into Drupal core since 10.0 runs against level one, and there is a meta issue or meta issues to get it bumped up to level two. So there is a issue. Tag PHPStan dash two. So if you're looking for some contrib work, a lot of it's pretty low hanging fruit. It's just there's a lot of it. Um, and that way Drupal Core can keep bumping up its level, which means that it has better code and core, which means that there's less bugs shipped. Um, if you have a contrib module on drupal.org or if you're using a contrib module from Drupal.org, which I think everybody is with GitLab CI, all contributed projects are running PHPStan at level zero, which means they're getting some baseline guarantee that the code is not breaking even if they don't have tests.
Right. There's no PHP unit tests. The code is not being executed. But if PHPStan. If PHPStan is scanning the code, that means it's in some way being loaded and verified. Um, that was added in the fall of 2023 and also with level zero, we'll dive into it a bit more. But that means the deprecation rules are running, which means that it will know if the contrib module is calling deprecated code or not as part of its CI checks. Um, as part of also at PHPStan can provide is there's a baseline file. And what this basically says is I have an existing code base. I want to add PHPStan but oh my, oh my. I've got like 300 errors and I don't want to fix all 300 errors by adding PHPStan. You add a baseline that says I am accepting this, these errors in this technical debt and I will build it down. I'll pay it off later and all new code will be fixed. So you can have a baseline that accepts those errors and you can go back and fix them over time, but always have new code adhering to your new levels of PHPStan.
And it's best explained in the docs on phpstan.org. And when the sides are uploaded, that is a link to the baseline. It's called um, Drupal core is using it. That's one reason Drupal core is taking a iterative approach, because I think at level nine, it's like a 15 megabyte baseline file, which would be great to have all new code matching level nine. But there's you know, that problem. So let's take that example of the hook node insert with the typo and run it like kind of walk through what PHP seven would be doing. So again here's a snapshot of the code. Um we have the typo that's missing the s. So we get a warning that says call the undefined method. And if the interface is public with the typo, great, we have an error. So we fix the error by adding the s and then PHP stands still says undefined method is published on entity interface. And then you kind of go like what do you mean? I know this exists. That's because your hook has the entity interface type hint. So you go in and you fix your hook and you say, oh, it's actually a node interface, because with hooks you own the parameters.
So you can fix the type entity to narrow it to the specific type. Now PHP sends us a thumbs up. You have a node interface. Node interface extends entity publishable interface. And that's where that method lives. So that way your hook is now correct and it's types. And PHP send says everything is good to go. Um, so there's PHPStan and then it's extensions. So we said like PHPStan checks if class exists. Um, it actually can detect incorrect namespacing. This is a story I love to tell from about 2016 or 2017 where Boyan and I were working on Commerce two, and we committed code on GitHub, and it pushed the Travis CI APIs like way back and Composer was new and Drupal, and the test passed in our machine, which were MacBooks. But on Travis CI it failed. And two senior engineers building commerce two spent about four hours wondering why it didn't work. Macs are not case sensitive. Linux is. And we had a typo in our namespace. Yay! If we would have had a tool like this, it would have been caught.
PHP CSS didn't catch it because it didn't know that the namespace casing was incorrect when it was used somewhere else. Um, so that's where PHPStan can save you on the little things. Um, the text function exists, methods on classes, and it can resolve variables and their types. So if you do have like a variable and it comes in through a method, um, it can detect what that type was throughout the entire method signature. So if it were to change types like oh, you just turned a string into an integer, it can warn you about that or as it gets passed through the call stack. And then there's the extension installer, which when you have that package added, it automatically configures PHPStan to register those extensions. Um, which simplifies using PHPStan a lot than it used to be. Um, and that's actually used by Drupal Core. So then there's the deprecation rules package as I just brought up a little bit earlier. So that allows you to detect usages of deprecated code. So when you've got those PHP docs with the deprecated symbol, this library enhanced allows PHP to recognize that document tag and then say it adds rules that say, hey, you invoked a method class, etc.
that's deprecated. Stop it and it will show the message from the deprecated one. So if you've used the upgrade status module, that's what it's using under the hood for all of its reporting, on top of a few extra things. Um, and that also became a dependency of PHPStan Drupal. And that means Drupal Core has it. One of the cool features is I worked on a contribution for deprecated scopes is what I'm calling them, and for the recording they can't see the air quotes. Um, but originally it worked with just an deprecated tag. But there are certain things that are considered the deprecated scope. Um, Drupal uses the Symphony PHP unit bridge, which has an At legacy or legacy tests, and those are considered to be deprecated scopes. So now that library allows you to say, hey, based off the context of the code, consider everything in this scope to be deprecated or not. So now you won't get deprecation warnings if it's a legacy test. Um, for Drupal 10 to 11, we have a new method called backwards compatibility call that makes it easier to write code that supports previous minor versions of Drupal core and the forward versions, and that also will support then that backwards compatible call.
PHPStan won't give false warnings about the deprecated code there, which means that contrib modules can now better support previous versions of Drupal core with deprecated code, and then also the new shiny version as well. And no more. Um, just anybody that has worked with major version upgrades. Is that weird dance of yes PHPStan I know that's deprecated code, but I need to keep it. That should be fixed now. And then we have PHPStan Drupal, um, which allows knowing the correct services from the service container, um, entity storage and query return types, checking if you're using internal classes, kind of warning like, hey, you extended this class, but in Drupal core it was considered internal, so there's no API guarantee for it. And a few of the things that I'll walk through down the road. Um, what's really cool is this last bullet about checking deprecated global constants from Drupal 9 to 10. We're cleaning up a lot of the global constants that were defined and deprecating them. Well, actually, before you couldn't know that they were deprecated.
We had to maintain that list manually. In a rule, the latest version of PHPStan can detect that, so we no longer actually have to maintain that list manually. Um, there is the PHPStan PHP unit. So if anybody does a lot of testing PHP unit allows providing a mock. And this allows PHP to understand mocks like, oh, this isn't a double object or whatever else, it's actually a node that you're mocking. Or if you're using self assert instanceof or is array, it knows all the different assertions and PHP unit, and then tells PHP stand that if this assertion ran and didn't fail to code, trust that assertion for what this type is. Um, and it's used by Drupal Core now. So as part of the level two initiative, there was like what did I put down? Oh, greatly reduced. I think it was like 2000 errors were resolved by adding this package to Drupal Core, because all the tests now, it understood how to scan the tests and analyze them. There's another package for PHP seven prophecy. So prophecy is another mocking library.
And this adds that same concept where every time that there's a prophesized object, PHPStan can understand how it works. Prophecy is not used as much anymore as far as I know, but there is still some Drupal code that uses it. I know I've written some in the past, so that could be a useful, um, package, but is not a dependency of Drupal core. And then there's one that's my favorite PHPStan strict rules, which adds a lot of defensive programming best practices like we've all used Drupal Drupal code, and there's a whole, if empty, if not empty check. And that, like, makes my eyes roll up. Um, this tells you you can't do that. And I've loved that to say, like, let's be more like, what does empty mean? It's empty zero false and empty string. Let's be more specific. And it really enforces that. And I really like having types in my code because I know it's going on. And that is one beauty about PHP is you don't have to be strictly typed, but you can be at the same time. And this allows you to start enforcing a bit of that.
And if you want to find other extensions, you can go on packages.org and look at extensions of type PHPStan extension like chipmunk has a whole bunch of extra rules. There's the greater PHP community, has a different extensions for all sorts of things, like um, band code. So if there's a certain function you don't want called, you can use that package and configure it. There's an open issue for banning the unique ID function in favor of something else. So that's being evaluated as well. So everybody's a developer and they want to play, although the Wi-Fi is kind of acting up, so maybe you can't play. Here's how you add PHPStan to your Drupal code base. Composer require dash dash dev Drupal core dev. That's it. Because it's a dev dependency of Drupal core, you just need the core dev metapackage, which I'm sure everybody has because you're writing tests for your Drupal code base already. What I think is really cool is just two years ago, this was the command. It was required PHPStan the extension installer.
PHPStan Drupal. And the deprecation rules and PHPStan Phpunit. And even before that, by another year there was no extension extension installer. So you had to like configure it manually to have all the extensions run. Um, so I think that's just really cool how far we've gone as a community to adopting this and writing better code. So once you have that installed, you just do PHP vendor bin PHP analyze dash dash level 2 or 3, four, five, six and then a path to the code and that will then scan the code, do some static analysis goodness, show you errors, or maybe you like the perfect developer. It says no errors found and you can say yeah. And here's an example of how I configure my PHPStan neon. Um, PHPStan uses the neon format, which is probably like the. Net framework. It's the YAML, just as far as you're concerned, it's YAML. Um, so you have the parameters, like I will always send it to level nine. I like to start at the top and then decide like, yeah, we'll accept it or not. I configure my paths.
So like the custom modules, the custom theme then includes I like to include bleeding Edge. I'm not sure how to really incorporate that to the slide yet, but basically PHPStan has configuration that turns on some bleeding edge experimental features. Um, Drupal core is using it because it has some performance and performance improvements, but it can also make things go a little haywire sometimes if it's a patch release. Um, and then I also that's also how you include your baseline as, as it include it takes it as like an extra configuration file basically. And the benefit of having a PHPStan neon is you just gotta run PHP vendor bin PHP standard. You don't need to type, analyze or anything else, it just knows these are the paths at this rule and go for it. So let's talk through some of the magic that PHPStan Drupal brings. One of the big things in the first start was auto loading. I brought it before that. Drupal is a bit magic. Take a normal PHP application, take Symphony Laravel, use Composer and then Composer dumps all those namespaces to the auto loader, and it knows how to access any class that's in the system.
Drupal doesn't do that because we have modules. It's dynamic. You could have like um, maybe you have the taxonomy module turned off. So the Drupal taxonomy namespace doesn't exist. And that's something that PHPStan Drupal tries to mimic, is the auto loading and bootstrapping of Drupal itself during static analysis without a database. A little tricky, a little kind of goofy, but the idea is that we want to be as true as possible. So that way you're getting a realistic result. Um, and it also will load like some of the legacy includes, you know, that includes like file Inc. and a few things like that will include currently it takes all the available extensions and registers them eventually. I'd like to be more specific to your site. So if you have 20 modules enabled, only those 20 namespaces are available. And then you could detect if you're using code and a disabled module or not. Um, the good old hook files, these aren't as common in D8 as they were D7, but they still exist like Views.in token Dot Inc, path auto Dot Inc.
It knows it tries to check if those files exist and load them. So that way the functions can be discovered and analyzed. And then also Drush includes as well. Although I think with Drush 12 and 13 this is less of a thing, but more for like ten when there's like the Drush Dot Inc or whatever it used to be. And then the service container. So we'll take all the services that yamls and it will parse them and say, all right, when you call Drupal backslash Drupal service and get like entity type manager, it knows it's entity type manager interface. Internally it's doing a service map that knows how to return the valid types. So that way you can detect if it's getting a deprecated service. We don't really encounter those as much as we used to, but take like Drupal eight to Drupal nine. The entity manager was deprecated and split into like ten services. Well, in the code, if you're doing Drupal service, Git or any of that, you didn't know if you had broken code or not, this would have let you say like, hey, you're fetching the deprecated service.
Actually, you should be using this one instead. And the benefit there is if you're using a deprecated method on that service, it knows instead of kind of going like, ah, I don't know what this is, so I'm going to not report anything at all. Um, there's a pretty cool entity integration. This is one of my favorites that a contributor gave in. Like, this was like one of the big first, like, outside of me contributions from folks. This is cool. So it contains a repository of entity information. So it's a little bit hard to see. But it says entity mapping block. Well here's the class for the block entity type. Um block content. And then node it says here's the node class and here's the storage class for that entity type itself. So when you do backslash Drupal colon, colon, entity type manager, get storage. And you say node like you pass node as an argument, it knows it's node storage, which means it knows all the special methods attached to it. Same with terms like terms have like get hierarchy and load parents or something like that in the storage.
So if you were to normally go Drupal entity type manager, get storage taxonomy, term load parents PHPStan I'm like, well entity storage interface doesn't have this method and you have to do all this extra work to say, trust me, it is this class now it just works. Some air quotes just works. And what's really cool is that, um, contrib modules can actually define this information. And in their composer.json put a little extra information in there and PHPStan extension installer will detect it. Um, there's a link that actually just is on the readme of PHPStan Drupal. So you can the example would be commerce. Commerce has like seven entities. Instead of maintaining that in PHPStan, Drupal contrib can own their entity type definitions for PHPStan to understand and be aware of.
>>:
So if you're doing custom entities and your custom modules, do you have to then go through. Composer to make that happen? Yes. No. So you don't have to go through Composer. Great question. So the question is I have a project my own custom entity types in my project would have to go through the Composer.json route. No, sorry to clarify, you can add this into your own PHPStan. So in your PHP send neon configuration file under parameters, you would say Drupal colon entity mapping, and then you would start adding your information in because all this configuration and then your own gets merged together. Um great question. I'm going to make sure I update the slides for that to show a better example of that. So so if you have your own custom entity types, you can add them into your PHPStan neon and then PHPStan will understand what's going on. Um, so as I brought up the entity storage class detection. So here this is like some of the test code just showing like, hey, any entity type manager get these different entity types and it knows what storage is being returned.
Which lets us do even cooler things when it comes to calling different methods on the entity storage like create page, it knows it's a node. If you call load, it knows it's a node or null load unchanged or load multiple. Um, one of the cool things about load multiple is might be covered on the next slide as well. But if you have a content entity, it's keyed by the entity ID and then it's the nodes. So it's an array of integer keys. And then the entities if it's a configuration object entity, those are string identifiers. So it will know that it's an array keyed by string. So it's an associated array of entity types which is important right. If you're doing operations like unset um like you want to like pluck an entity out, it could warn you like, hey, you tried to pluck out a string from a content entity type, which means maybe your mappings are wrong, or maybe just you're like, oh shoot, I forgot. I'm working with a different kind of entity type. All those little things, right? Like you do and you don't really think about.
It's there to like be your backup, I'm saying. So the entity entity queries so it determines the return types like here you say. So here it can be any string versus string string. Um it knows if you're doing an access check or not. And Drupal ten, one of the biggest changes that's kind of like hard is that entity queries are forced to identify their access check. So you have to always call access check. And that broke a lot of things. So PHPStan tries to understand that it is a very tricky situation, but it's like 50% of the use cases are covered and will like warn you like, hey, you have an entity query, you forgot to call this method. Um, it also knows if you call count. So if you call a count it says hey, this execute returned an integer versus an array of different values. Um, one thing that I think is cool. Also some render array checks. One of the coolest features about Drupal is the fact that you don't have to write HTML to make output. You write a render array and we have certain rules about the renders array and PHPStan Drupal can help you enforce those.
So with Drupal Garden, which I'm sure a lot of people remember, there is a way like our render system has callbacks and then Layer Security was added saying I will explicitly tell you what's an allowed callback or not. And this rule will say all right inside of pre render post render access callback lazy builder. Is that callable a closure or is it closure being like an anonymous function or is it defined or is it definition inside a class of trusted callback interface and render callback interface or Drupal ten we now have an attribute which is a PHP eight. Does that method implement the trusted callback attribute so it can do a lookup and warn you like hey, in your form you have a post build, or actually I think post bill is covered also, but in your lazy let's do lazy builder, your lazy builder, you have this callback, but it's not actually explicitly registered. So without having to run the code and see it crash, PHP stands warn you. Or if it did crash, you don't know what's going on and PHPStan.
Oh that's why. Um, so it does support the normal service name callable format. It's a horrible word way to say it. But you could have like my service colon and then the method name. That's like a special Drupal ism that says service name and then the method. So it knows how to parse that format. Um, it also warns you if you use a closure in a form class. Now that's really important because closures, anonymous functions can't be serialized, and certain times the form might get serialized and put into a cache, like if you're doing Ajax in your forms. So it warns you and says, hey, there's a good chance your form could explode because you did this. Um, loaded includes I don't see this as much anymore, but there are times where people put functions in a separate file and then they call module load include, which is deprecated for removal, and Drupal 11, or the module handler load includes. When PHPStan Drupal sees that code, it will go require the file for you. And then again the idea being like we're going to run and analyze your code like Drupal would, because before if it hit a function, PHPStan said undefined function, which is true because it's not defined in the normal auto loaded sense.
This brings it into scope. So that way it's running like your code actually would. Um, stub files. So PHPStan s idea of a stub file, which is essentially saying the PHP doc for the original class is wrong. I'm going to tell you what the correct PHP doc should be, or take Drupal Core. They may not want to say I don't want all the core committers and like the coding standards might say we don't want to add at PHP, stain, dash all these things because that's not a standard PHP doc. So the stub file allows PHPStan Drupal to say, here's what things actually are for PHPStan. Or when it comes to fields using generics. So templates and generics half the time over my head I'm kind of getting them. Now some people it clicks. For me, it's halfway there. But what this is showing is we have a field item list interface. So entities contain fields. Each field is actually a list of field items. So what this is showing is that field list item interface is a template of tea. Meaning tea is field item interface.
So it's a list of field item interface that extends list interface. And just think of the tea as like the variable. And then below we can see that list. It's extending list interface which says that template tea is type data interface. In the earlier days of PHPStan, when working with entities, the PHP doc everywhere says type data interface. Great, but we know they're fields, and it would always argue about the different methods when working with fields. So this little magic here makes PHPStan understand that. Oh, and your node when you call Git, or even when you do like the arrow field, underscore the name it knows, like, oh, that's a field item list. Great. And that it has magic methods that say when you call value that is actually doing all this magic stuff underneath to get that field value. So this a little bit of PHP doc made PHP understand how entities and fields work. Um, which props to King Dutch at Opensocial. Does he help push a lot of this through? And they kind of like show like here's an entity reference item list.
So at the top this customize the field item list interface to say that, hey, the values are actually inner entity interface in there and just extends it even further down the the way, which hopefully, maybe we can get this pushed into core. I don't know the full steps of that, but like think of it this way PHPStan Drupal is a treasure trove of contributions that can go into Drupal core to improve some of the PHP docs. Um, now that Drupal coder is not a blocker because before peach with Drupal code coding standards, it didn't allow certain things and now it does. Um, PHPStan with stub files also lets you define custom types. So this is like one of the custom tags PHPStan hyphen type. So you can create like a shape and then use that shape throughout a class. So with cache back and interface. So whenever you get a cache object it's always a generic object with certain properties on it. This at the top says cache object has data of mixed because we don't know what the content is. There's a created integer integer timestamp tags that's an array of strings if it's valid, etc.
and then it says on the Git method it's going to return a cache object. It's not a real class, but we've told PHPStan that it is. And PHPStan will go, oh, you receive something from the cache back end. I know it will have these five properties and I won't yell at you for accessing them. Or I'll say, hey, you try to work with the created timestamp as if it's a string, but it's actually an integer or items like of that sort. Same with like get multiple. It knows it's an array of those items and that's no PHP code there. That's just the PHP doc. To make PHP stand a little bit more aware of how Drupal works. And then there's some miscellaneous awesome sprinkled into there. Um, there is a thing called the class resolver. So if you've ever looked at the content moderation or workflow modules, they use this thing called the class resolver. It's not like when you have a class that uses, um, dependency injection, but it's not a service. You would use this class. Oh, and hey, the example is from workspaces.
I was looking at the notes so Git instance from definition. Essentially it says, hey, when somebody calls this, the class that they've passed in is the class that's returned. So that way when you do get any get entity type build or entity type, alter PHPStan knows that you're actually calling a method from the class that was passed in, or it will warn you like that method doesn't exist. You got this class, but it's not really there. Like the class doesn't exist or the method doesn't exist. Um, any access results. So this is different than entity queries. So the entity access system supports returning as a boolean or an access result object. And a part of that's like backwards compatibility. So that way it defaults to being a um it defaults to being a boolean return. So if you call access with just like the two values of the object and then the operation, it returns a boolean. Or if you pass in all the things like entity operation account. And then true is like return the object. PHPStan will know that you're getting an object back.
And why does this matter? What if you do if access? If create access, do something. Um, if it's a boolean, there's a chance it could fail because it's false access result. Forbidden is an object, which means it will always pass because it's not empty. That's a big security. Whoopsies. Right? Like, oh, hey, it's an object and it always passes. So this allows PHPStan to be aware that you're doing faulty logic in your conditionals. And again, that's one reason you should be running it at a higher version of PHPStan. I can't remember exactly what level introspection of if conditionals kicks in. Maybe let's say it's four. That's a reason to get up higher, because you'll have better safety checks around your access control. Amongst other things. Um, extending internal code. So in Drupal there are several classes that have at internal at the top, and this rule will flag an error if you're using internal code outside of the namespace. Um, as one of the maintainers of JSON API resources, we did this.
We had like internal unstable code and then a public API. We want to warn people like if you extend this, it will break. If you use it outside of our API, it will break. So shared namespace could be Drupal core. If Drupal core is using internal stuff, it's fine. But if a module were to use something from Drupal core that's flagged internal, it would throw an error. A lot of times you see this with forms because forms aren't guaranteed, so it can be a bit noisy, but I figure it's better to see the warning and accept it than to not know it's there at all. So the second part of the namespace wants to match because it's general pattern. It's Drupal is always the root part of the namespace, and then it's the module name core component, the theme. And that's the rule for that. So again you saw how like it's going to make your code so much better. And again let's just show how to add PHPStan to your code base. Again you just got to require the dev the core dev meta package. And then run the analyze command with the level.
So let's talk about what's on the horizon for PHPStan Drupal, um, improved container support because now Drupal is advancing the container supporting auto wiring. So instead of in your services YAML, where you're like, here's all the arguments and certain things like that. The Symphony dependency injection injection container can know how to automatically do that for you. And Drupal now supports that. But PHPStan Drupal is doing it by hand still, so that needs a big refactor to make it actually work if you're using auto wiring. Um, I have in progress a Drush command to generate your entity mapping and field information. So I was brought up before, but what about my custom entity types? It's kind of a pain to go there and have to type that out. But what if there's a Drush command that PHPStan Drupal can provide that says dump it, just dump in the the entity types and also my field definitions. So that way PHPStan Drupal can say, oh, you fetched field address. That's actually field item list that contains address items.
And then it's even smarter about the properties that are available. It's in progress. I think it could work. I just haven't gotten back to it yet because there's a lot of other bugs. Um, this was first written in 2019 or 18. Yeah, 18. Um, there's some plugin manager rules in there that could use some cleanup because they're a little bit old and flaky. Um, better Drush support. Actually, I forgot to remove that because the latest version of PHPStan took care of that for me. Um, so it is also like, used for Drush, but I figure we can consider Drush code Drupal at this point. And then any of your suggestions, you know, as it comes in like, hey, I read it with this code, it didn't work or I wish I could do this way, you know, um, long wave, one of the core contributors just found one where if you do lock acquire two times in a row because it could be when you get a lock, it could say lock acquire. If you can't get one, you wait and then you try to acquire it again. PHPStan actually said it considered lock acquire to be truthy all the time.
So the second time you call a choir, it was like, uh, duh. It's true. Like work on it. Well, there's a concept called pure and pure. So we had to do a stub file that said, actually, it's an unpure method that every time I call it, it's not always going to return the same value. It's like there that was a quick fix I got in this like earlier today or, um, you know, going back to the whole securing access results, PHPStan has rules that say in your if conditional, that it might always evaluate to false or evaluate to true on access results. There's a static method of allowed if forbidden if well, an if statement is a great way to screw something up on accident. So I want to see if there's a way for PHP send to analyze your condition for the same thing of you have an allowed if and it's always going to evaluate to true, which means your code is not as secure as you think it is, which I think would be a huge benefit for contrib and personal and client projects as well. So like those things like if you have ideas like, oh, I could have my junior developer did something and I'm kind of sick of always reviewing the code and telling them I'm sick of being the bad guy.
Which is one reason I fell in love with PHPStan is we can codify our processes and our knowledge and not tell people they're doing something wrong the entire time. And also, senior developers don't have to worry about that cognitive load. So anything that you come across, like open issues, I'm all for it. Um, one thing I brought up about, like Drupal going to level nine in the 15 megabyte baseline file that's actually being actively discussed. I don't think it's a bad idea, because we can prevent that baseline file from being distributed with core. It doesn't have to be download like, it doesn't mean everybody's going to deploy into 15 megabyte file to production, unless you're checking out the source code along the way. Um, but there is an active issue that's weighing the benefits of going to level nine or maybe level seven. Um, so that way all new code to Drupal core is at a certain level, because there have been issues that have been committed causing regressions or that have side effects that weren't caught, but would have if PHPStan was running at a higher level.
And unfortunately, it's not bumping up levels fast enough. So if you are interested and the slides are uploaded, that link will go to that issue if you want to follow along. That is one that King Dutch from Opensocial is pushing. Um, Opensocial is a huge user of PHPStan. Um, and they do a lot of cool things there. Some resources if you're interested in getting. If you want to like, chat or learn more, there is the PHPStan channel on Drupal slack so you can hop in, ask questions. I've been trying to push people there. Now that there's like GitLab CI running it, I'm seeing a lot of questions and the GitLab channel or the testing channel come over here. There's a little bit more like it's consolidated. Um, every time I push a release I've got GitHub hooked up so you can see it releases in and said, like, I'll go test it out. Hey. Hey, Matt, you broke something. So we need another patch release going on there. Um, which is one thing that I did not cover in here. New rules are now behind feature flags until I make a minor release.
So there's one of all tests must end in test suffix. Or there's some rule like that that Drupal core needed. Well, you have to add that flag to your PHPStan neon. Um. There's a new one coming out. Where in your forms, you can't use a private property because they can't be serialized, and you can't use a read only property because it can't be serialized. So there'll be a new rule coming out that warns you that if your form or any class using the dependency serialization trait and it warns you like, hey, your properties won't actually be serialized and your site will go boom, that will be behind a feature flag. To prevent some of these, CI builds from failing until they choose to opt in for that, or there's a new minor version. Okay. Um, so there will be there is now a little bit of method to the madness when new rules are added.
>>:
And then a few links. So there is documentation for PHPStan on drupal.org. Um, links will be hard to read up here again on the slides. When thinking about everybody was asking how do I use this? I don't want to use the GitHub wiki. It is managed on GitHub for the code, but I feel like this belongs on drupal.org because it is much more collaborative. Um, GitHub's access control is really a pain for that kind of things. So there is an open wiki there, so that way everybody can contribute to it. Like somebody added for PHPStan in Drupal core beyond just using it for yourself. Um, phpstan.org there's a blog where the maintainer writes great insights and also like all the advanced things you can do with it. Of course, the GitHub repository is more common. PHPStan Drupal. Um, Bram can't remember the real name. One of the contributors that added the entity storage stuff had a great talk about PHP static analysis, static analysis 101 that dives into like, what is the abstract syntax tree? And some of the more advanced topics that I kind of just like glance over and then from Drupal Dev days.
Last year. Um. From factorial. Yes. Factorial. They have a great talk about introducing PHPStan to a large scale project. So they had a project that was started and didn't have PHPStan and how they integrated it and use the baseline, how they sold the customer on it. So if you do have a client and you're like, we should make this safer. And they're arguing like, well, I don't know about the cost and what about this? It's like, well, here's how we can sell you on using it without incurring a lot of upfront work, but guaranteeing better code throughout the delivery cycle, which means less bugs. And they save money because it's always more expensive to fix a bug after it's introduced. And that's it. So thanks for coming to the talk. Any. Uh. Any questions? What does it look like to set a baseline file and then go back and rework the text documents? That would be a great video to add. So when you generate the baseline, you do PHPStan analyze and you generate a baseline. So that creates the file.
And any time a new error is added or actually let's talk about like working on the tech debt. Go look at that. Review it. I've done that for Drupal Core to kind of get inspiration on what I should build for PHPStan Drupal. Look at an error like, I'm going to go fix that. And then when you run PHPStan, it will say this error, this ignored error isn't ignored anymore. So then it fails. So even though you accepted those errors, PHPStan will fail when there's an ignored error that isn't true anymore. So that's what it looks like. I can go fix it and it will say either the error has changed like name or any of that sort, so it's either removed or the error message change. It warns you about the ignored error not existing anymore. So then you just go through, find an error, fix it, run PHPStan, verify that the error is gone, or delete that line from the baseline yourself. Run PHP and hack away at it that way. So you're reading. You're reading your ignore file to try to locate what needs fixing.
Climbing the walls or. Oh yeah. So like when working against a baseline, I would just read it myself. It's like, all right, what did we accept previously that we want to work on? Um, I know I have a project at Acquia where we have a giant baseline and there's tons of things. I'm like, you know what? Let's just accept it. And we have these things called innovation days. Every month. I'm like, look, let's not do ticket work. Go look at the baseline and like, find something interesting to just whittle away that tech debt. And I'm a firm believer in having days like that. Like it's all great and fun about innovation and fixing bugs, but sometimes you just want to make things better. And so like the baseline is a great way. Like also if you do like level nine, you're going to get lots of errors, which means that you can create that maintenance sprint to give like developers a little break, have a little fun, like, oh, how can we fix this bug? Or why did it air in the first place?
>>:
So you showed the slide with the stubs. And some examples. Were those examples already included in in PHP? Drupal PHPStan Drupal. Those are there or not? Yes. So the question was about the stubs that were shown a few back. So these are in PHPStan Drupal right now. So these are all in there. Um, there's a lot of different ones in there. So all about half of the core field types also have them. So like um, the file item knows that there's the URI property on the file field itself. And I have about ten issues. They're all labeled as good first issue and help wanted for adding stub files for the core fields. Like if you want to contribute and get your feet wet, um, you can talk to me at the unconference this afternoon or at Contribution Day on Friday and see about like, hey, how do I actually write a slug file? How can I help improve? PHPStan Drupal. Um, and then maybe, like looking at the existing ones and say, can we get Drupal Core to take these improvements now? Because maybe they'd be willing.
>>:
This is. Was that a logging? Well, it was logging. Like what? What kind of logging does it do? Oh. Got it. What kind of logging is PHPStan do? So by default it will. I'll just print like, lines on the like lines to the terminal, but it actually supports JUnit Teamcity maybe Team City, but it supports all the various XML formats. So you could actually feed it into a code quality report tool. Um, should take a, uh, if it's if you look at the GitLab CI templates for Drupal.org, the PHPStan job actually runs it four times. PHPStan has a cache. So if you run the same files like three times in a row, it's expensive once and then it's boom boom. It's real quick. They do it once to print the output to the screen, once to generate a JUnit file, and one to generate like another file. And there's different output formats. So that's where the PHPStan docs will show you the different output. Formatters I know I've used it for JUnit to get, um, code quality tools to read that as well, and it also supports out of the box GitHub actions.
So if you do use GitHub actions, you don't need to do anything special. It will automatically dump that. So that way your pull request shows the errors in line in GitHub, which is really cool that the tool itself does that for you. Any other questions? All right. Cool. Well, thank you for coming and enjoy lunch next.