Project Cleanup Setup0:00
Automation Now that we've automated the automation, it's time to actually start building some custom scripts. And in the last video, we noticed that I left this printr statement when I made a commit. This is kind of a classic developer mistake. It's rare that you would actually want to leave these calls in your code. So let's write a custom script to automatically sniff these out and warn us. Before doing that, I want to do a little project cleanup. Let's make a source and a scripts directory. And I'm going to move our linter into the scripts directory.
Let's make a source and a scripts directory. And I'm going to move our linter into the scripts directory. And before I forget, let me go ahead and update that githook for the new path. We'll make sure to reference that now under our scripts linter. And for the source files, I'm just going to copy over some pre-made examples that I've made for us for this video. All right, let's see what we have here. We moved our scripts into the scripts folder, and we now have these source files. And in here, I just have a bunch of different code examples.
Creating Debug Call Script1:05
and we now have these source files. And in here, I just have a bunch of different code examples that use things like var_dump, print_r, var_export, and for Laravel folks, the good old dump and die. What I want to do is build another script that's going to sniff out these calls. So let's copy our linter, and we'll just call this debugCalls. Great. Let's see what we can do here. I'm going to start trimming down pieces of this file. We'll just do a little first pass here of things that we're not going to care about.
I'm going to start trimming down pieces of this file. We'll just do a little first pass here of things that we're not going to care about. So we probably don't care about really any of this code. But I do imagine we're going to loop over these files in some way. We're probably not going to parse the error in the same way that we did for the linter. We will likely display the error, and we want to keep find files. Now, this is actually a good place to start. And something I want to point out is the finder actually does have a contains method. And we can actually pass this a pattern, which would really do a regular expression search on the file's contents.
Scanning Files for Matches2:06
And we can actually pass this a pattern, which would really do a regular expression search on the file's contents. Normally, that would be where I started. But since we can actually pass in changed files for our pre-commit hook, we won't really be able to use this directly here. So that means that we're going to need to loop over these ourselves and do some similar logic to check the file's contents. So let's go ahead and get the file's contents with good old file_get_contents(file). And now we can scan the contents in a similar way. So we'll call preg_match_all this time to find all matches.
And now we can scan the contents in a similar way. So we'll call preg_match_all this time to find all matches. We'll pass this a pattern. I'll come back to that in a second. We'll pass it the contents. And of course, we want those matches. And now we can say if $found, then we know that we would have some kind of failure. And we would probably want to call displayError with the $file and whatever else. I don't know yet.
Building the Regex Pattern3:04
And we would probably want to call displayError with the file and whatever else. I don't know yet. Okay, let's talk about this pattern. This is actually a little more straightforward than the one we wrote for the linter, but it's going to introduce some new syntax. So we're going to want to do a captureGroup. And within here, we can pass all of the different debug functions that we would want to check for. So things like print_r. And we can do some alterations here with a pipe or an or.
So things like print_r. And we can do some alterations here with a | or an or. So print_r or var_dump or var_export or dd. I think that's all of them, but let's check our little example. var_dump, print_r, var_export, dd. Good, that seems like all the ones we care about for now. And we'd want to make sure that that was followed by a opening parenthesis. Now, this is actually a regular expression character, so we'll need to escape that. So this gives us kind of our anchor,
so we'll need to escape that. So this gives us kind of our anchor, but we need something at the beginning to make sure we're boxing in this pattern the way we want. Otherwise, it could match things like print_r, and we wouldn't want that. So for simplicity, we could just use the word boundary shorthand. So let's see what we found. We'll do a good old print_r on our matches. And let's clean this up so we don't have some kind of error. We'll just pass it that for now, and it seems like it's still not happy. That's because we're actually not matching the function signature,
We'll just pass it that for now, and it seems like it's still not happy. That's because we're actually not matching the function signature, so let's change this to something. So let's actually try to run this. We'll do scripts and debug calls, and it looks like we have some issues. scripts, debug calls, online 16, debug calls. Interesting. Oh! It looks like it's not getting the correct path.
Fixing Finder Project Path4:57
Oh! It looks like it's not getting the correct path. It's just searching locally instead of the whole project. I think I know what's wrong here. If we go down and take a look at the finder, we're actually using this DIR constant. Now that we moved things underneath scripts, that's not actually going to be our project path. I think the simplest thing to do here would just be to say dirname, and that way we go up to the parent directory.
I think the simplest thing to do here would just be to say dirname, and that way we go up to the parent directory. Since we know that scripts is one level deep, this should be okay, but you could do something else like get the current working directory. Again, I'm okay with dirname because I know my project's structure. All right, let's try that one more time. All right, if we ignore some of our undefined variable warnings, we actually do see the print_r, and it is finding the dds in all the right files, so var_dump finds the var dumps.
and it is finding the dds in all the right files, so var_dump finds the var_dumps. If we scroll up here to our all file, we'll see that it did find all the different instances. So this is pretty good. Let's clean up this output just a bit. So if we go back to our matches, we can see that preg_match_all by default gives us a multidimensional array, and the first dimension is going to be the different capture groups.
gives us a multidimensional array, and the first dimension is going to be the different capture groups with the zero index being the entire match. So we should be able to pass in our second match at index 1 to get all the matches that it found in the file. So let's go down to displayError, and instead we'll turn this into an array of the different calls. And instead of saying lineNumber, we'll say containsCallsTo colon, and let's just implode those different calls. So implode, we'll give ourself a nice little separator and calls.
and let's just implode those different calls. So implode, we'll give ourself a nice little separator and calls. All right, let's see what this looks like. Just like our linter, we get the script that's offending, so we'll see that our linter contained that print_r calls, and of course all of our different fixture files underneath source have the different calls that they contain as well. One little quick thing we can do to clean this up, instead of all of these calls being duplicate, let's just make those unique, so we can say array_unique.
Limitations of Text Search7:08
instead of all of these calls being duplicate, let's just make those unique, so we can say array_unique. And if I run this again, now we get just the different calls that are in that specific file. This is a pretty good script. It's probably fine to do what we want, but there's a lot of different ways it's brittle. Let me point a few of them out. If we go take a look at something like var_export, first of all, we could actually just comment out these lines.
If we go take a look at something like var_export, first of all, we could actually just comment out these lines. Technically, these don't run. They may just be some kind of quick reference for a future developer. But if we run this again, we'll see that we still contain calls to var_export, and that's because we're just doing a simple text-based search, and that has no concept in the way in which php actually works. Now we could write a regular expression to probably figure these kinds of things out, but let me tell you, it'd be a bunch of line noise.
Now we could write a regular expression to probably figure these kinds of things out, but let me tell you, it'd be a bunch of line noise. The other thing I want to point out is actually this isn't a bad call, and it's because we're passing a second argument of true, which actually returns the value instead of displaying it, so it can be assigned to a variable. So ideally, our script shouldn't report this particular line. To truly make our script more accurate, we're going to need to actually analyze the code. So, I hope you enjoyed this video.
