Scenario
Assuming that today, I have a method sleep()
. This method takes in the number of seconds as an argument. Typically, we would write it like this:
<?php
public function sleep(int $seconds)
{
//
}
However, what if a negative value is passed as an argument? This is obviously not valid, but it can be done, leading to unexpected exceptions being thrown.
Therefore, we would generally rewrite it as follows:
<?php
public function sleep(int $seconds)
{
if ($seconds < 0) {
throw new InvalidArgumentException();
}
//
}
Problem
While the above approach does solve the issue, what if we have many methods that take in $seconds
as an argument? Do we need to write many if conditions to validate them all?
Solution
# Using types for validation
Perhaps, we can modify the code as follows:
<?php
public function sleep(Duration $seconds)
{
//
}
The core concept is that when we find an argument that has a special meaning, we can consider converting it into a simple class that represents a specific type. While being reusable, this class also increases readability.
# Type implementation
For PHP 7.4
<?php
use InvalidArgumentException;
final class Duration
{
public $seconds;
public function __construct(int $seconds)
{
if ($seconds < 0) {
throw new InvalidArgumentException();
}
$this->seconds = $seconds;
}
public static function seconds($seconds)
{
return new self($seconds);
}
}
For PHP 8.1
<?php
namespace App\Types;
use InvalidArgumentException;
final class Duration
{
public function __construct(public readonly int $seconds)
{
if ($this->seconds < 0) {
throw new InvalidArgumentException();
}
}
public static function seconds(int $seconds)
{
return new self($seconds);
}
}
Usage
<?php
sleep(Duration::seconds(5));
Throws exception
<?php
sleep(Duration::seconds(-5));