Published in
3 min readJul 21, 2023
# 情境
假設今天有一個 method sleep()
, 這個 method 帶入秒數, 一般來說, 可能會這樣寫
<?php
public function sleep(int $seconds)
{
//
}
然而, 假如 args 帶入 -1 呢? 這顯然不合法, 但卻可以這麼做, 且會造成預期外的 exception
因此, 通常會改寫如下
<?php
public function sleep(int $seconds)
{
if ($seconds < 0) {
throw new InvalidArgumentException();
}
//
}
# 問題點
上面的做法, 確實解決了問題, 但如果在很多 method 都會使用到 $seconds 當作 arg, 那是不是要寫很多個 if statement 來驗證?
# Solution
# 利用 type 來驗證
或許, 我們可以修改程式碼如下:
<?php
public function sleep(Duration $seconds)
{
//
}
核心概念就是, 當發現一個 arg 具有特殊意義時, 可以考慮將這個 arg 轉換成 功能單純的 class, 這個 class 代表一個特定的 type, 在可被複用的同時, 也增加了可讀性
# type 實作
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);
}
}
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);
}
}
使用範例
<?php
sleep(Duration::seconds(5));
arg 錯誤時會 throw exception
<?php
sleep(Duration::seconds(-5));