Even if you never touch a Laravel installation, I highly recommend a subscription to Laracasts, the video series by Jeffrey Waye. It is filled with tons of videos that are not specifically about Laravel and everything to do with coding well. I return to it often. The one that has stuck with me and you will see in all my code is Don’t Use "Else".
If you recoil with the words heresy and blasphemy on your lips (I did too when I first heard it,) bear with me a minute. I understand the "else" is one of the pillars of any programming language, but by removing it from my code it becomes cleaner, legible, extendable, and reusable. Just this one rule.
Let’s look at a "before" example (see the output here.) Please keep in mind I would never, ever, ever put a class in a file with something else – this is for demonstration purposes only.
<?php /** * "Before" script to demonstrate why we don't need "else." */ $some_array = [ 'foo' => 'bar', 'baz' => 'boz', 'blah' => 'bleah' ]; $cls = new UselessClass(); echo $cls->uselessFunction($some_array); /** * Class UselessClass */ class UselessClass { /** * UselessClass constructor. */ public function __construct() { } /** * @param array $some_array * @return string */ public function uselessFunction($some_array) { $response = ''; foreach ($some_array as $key => $value) { if ($key == 'foo') { $response .= "$key has a good value $value<br>"; } elseif ($key == 'baz') { $response .= "$key has a good value $value<br>"; } else { $response .= "We don't talk about blah here.<br>"; } } return $response; } }
One of the things I do to move toward SRP for every object, method, or function is to extract out the nested inner logic into it’s own method/function. We do that in version two and you can see the result is the same:
<?php /** * Version 2 script to demonstrate why we don't need "else." */ $some_array = [ 'foo' => 'bar', 'baz' => 'boz', 'blah' => 'bleah' ]; $cls = new UselessClass(); echo $cls->uselessFunction($some_array); /** * Class UselessClass */ class UselessClass { /** * UselessClass constructor. */ public function __construct() { } /** * @param array $some_array * @return string */ public function uselessFunction($some_array) { $response = ''; foreach ($some_array as $key => $value) { $response .= $this->outputLine($key, $value); } return $response; } /** * @param string $key * @param string $value * @return string */ protected function outputLine($key, $value) { if (in_array($key, ['foo', 'baz'])) { return "$key has a good value $value<br>"; } else { return "We don't talk about blah here.<br>"; } } }
We’ve reduced the lines and logic of the public function by extracting the inner logic from the foreach into outputLine(). Because (in this case) the elseif is the same as the if we have eliminated one line (which we could have done in the original logic, but go with it.)
But wait . . . there’s still an "else." What we need to think about is why do we need the else at all? The first lines of outputLine() return a value if the condition is met. The else is never really executed. Why do we even need an else?
We don’t. The result is the same, but we’re one line more simple and one line more legible.
<?php /** * Version 3 script to demonstrate why we don't need "else." */ $some_array = [ 'foo' => 'bar', 'baz' => 'boz', 'blah' => 'bleah' ]; $cls = new UselessClass(); echo $cls->uselessFunction($some_array); /** * Class UselessClass */ class UselessClass { /** * UselessClass constructor. */ public function __construct() { } /** * @param array $some_array * @return string */ public function uselessFunction($some_array) { $response = ''; foreach ($some_array as $key => $value) { $response .= $this->outputLine($key, $value); } return $response; } /** * @param string $key * @param string $value * @return string */ protected function outputLine($key, $value) { if (in_array($key, ['foo', 'baz'])) { return "$key has a good value $value<br>"; } return "We don't talk about blah here.<br>"; } }
Now imagine we want to maintain the original functionality of UselessClass() but want different output. We also want to send it a different array. Normally we would go in and modify the code, wrap stuff in more logic blocks, and it would work. Eliminating "else" has led us to extract one function that now allows us to extend the original class and override outputLine() with different functionality. In this respect we can now adhere to the "O" in solid, open for extension, closed for modification. See the result here, and we never touched V3 of our code (we could have extended V2 also.)
<?php /** * Version 4 script to demonstrate how our refactor can now be extended. * This example won't execute on the server unless I instantiate after * the class declarations, see below. */ /** * Class ExtendedUselessClass */ class ExtendedUselessClass extends UselessClass { /** * Note because neither constructor does anything, don't need it. */ /** * @param string $key * @param string $value * @return string */ protected function outputLine($key, $value) { if (in_array($key, ['this', 'theother'])) { return "$key is $value<br>"; } return "Forbidden words are, well, forbidden.<br>"; } } /** * Class UselessClass */ class UselessClass { /** * UselessClass constructor. */ public function __construct() { } /** * @param array $some_array * @return string */ public function uselessFunction($some_array) { $response = ''; foreach ($some_array as $key => $value) { $response .= $this->outputLine($key, $value); } return $response; } /** * @param string $key * @param string $value * @return string */ protected function outputLine($key, $value) { if (in_array($key, ['foo', 'baz'])) { return "$key has a good value $value<br>"; } return "We don't talk about blah here.<br>"; } } $some_array = [ 'this' => 'that', 'theother' => 'thing', 'forbidden' => 'words' ]; $cls = new ExtendedUselessClass(); echo $cls->uselessFunction($some_array);
This one rule – Don’t use "else" – has changed how I code forever. It is not the only tool I’ve learned, but it is always where I start. Of course, in a large code base where it could break something, we have to be very cautious about how we apply it, but it’s the most simple and safest place to start untangling the Big Ball of Mud.