Refactoring #8: What is dead may never run
Removing unreachable and redundant code will benefit you massively over time. There's a tool to do this automatically for you.

Search for a command to run...
Removing unreachable and redundant code will benefit you massively over time. There's a tool to do this automatically for you.

No comments yet. Be the first to comment.
Testing is almost always difficult when developing applications that interact with external services, APIs, or complex features. One way to make testing easier is to use stub classes. Here's how I usually work with them. Quick intro on benefits Stubs...

We're upgrading from Laravel 9 to 10, and PHPUnit 9 to 10, and, if all goes well, we'll top it off by migrating to Pest, the latest version. To keep the positive vibes on I'll skip an upgrade from PHP 8.1 to 8.2, just because I don't want to restart ...

GitHub's 2000 minutes per month of free usage of GitHub Actions is usually enough to handle light workflows. However, as more tech is run automatically, we are forced to upgrade to a paid plan or optimize our workflows. Currently, I am running Rector...

A nice refactoring I've learned recently is to utilize types in conditionals. For years I’ve been doing if (!empty($posts)), but Rector, a tool to automatically refactor code, changed that to if ($posts === []). The main advantage of using $posts ===...

Laravel 10 is making the headlines these days. However, many apps are stuck in older versions, or at least still use the syntax and methods of older releases. One of the most significant changes introduced in Laravel 9 is the syntax for accessors and...

It's important to take a good look at your code and clean up when you're done with it. Once in a while, we tend to forget this little detail and just move on, leaving behind trails of unreachable statements.
Here's a very blatant example of a dead piece of code.
{
$user = auth()->user();
return $user->posts;
// This line will never run
$user->posts->each->publish();
}
The last line above will never execute, and while this type of code looks like a very rare occurrence, it still shows up a lot. There is this automated tool called Rector that is fantastic at finding dead code like this and removing it, or letting you know of its existence.
Rector also unearths other dead code that is not completely obvious at first sight. This one below is very common, actually.
/**
* @param GeocoderInterface $geocoder
*/
public function __construct(GeocoderInterface $geocoder)
{...}
The PHPDoc is expressing the same information that is clearly stated in the method declaration. A dev can easily see that the method needs a GeocoderInterface object, the extra comment does not tell more than that. Same for an IDE, you will get the autocomplete you need without the comment.
One more thing I don't like about these redundant docs is that they often 'lie'. Take this for example:
/**
* @return User
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
This keeps me up at night. This Eloquent relation has a return type of BelongsTo, but if you use it as a method $post->user() somewhere in code, the IDE will wrongly suggest you autocomplete options that belong to an Eloquent Model. It will be fun trying to find these bugs when they happen in runtime, so just remove the comment entirely.
If you find yourself doing this often because you want some more autocomplete options when accessing the actual model $post->user, consider annotating it, like this:
/**
* @property User $user
*/
class Post extends Model
Another piece of dead code is the Laravel framework's default stubs. They're there so we can easily input our dependencies. What do we do if we don't have any? Nothing, we just leave it there, because we're lazy.
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
}
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
No harm in keeping them, but if you're not injecting anything, frankly, wipe these suckers from the face of the earth, they're just taking valuable space and pushing the real code down below. You can also change the default stubs by running php artisan stub:publish.
Dead code candidate #4 is tricky. Usually, it's safe to remove the redundant check like in this simple case:
if (! auth()->check()) {
return 'not logged in';
}
// This second condition is always true
- if (auth()->check()) {
- return 'logged in';
- }
// You can just execute the code without the condition
+ return 'logged in';
However, there may be cases where a check like that is needed if there's stuff happening behind the scenes, like in this uninspired example:
if (! $user->canPost()) {
...
return false;
}
...
$this->updateUserPermissions();
// You might want to keep this check
// even if you've checked at the top
if ($user->canPost()) {
return true;
}
A tool like Rector won't magically understand the underlying sorcery that is happening and will simply suggest removing the last condition. To silence it, simply add this comment:
/** @noRector \Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector */
if ($user->canPost()) {
return true;
}
That's it for the dead code. You killed it. I've also posted about other spells Rector can cast for you, like using updated syntax from PHP 8.1 and above, auto-importing class names in the whole codebase, etc. Check out their site, they add refactorings weekly 🏠🔥.