Ray Lee | 李宗叡
Learn or Die
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));

--

--

Ray Lee | 李宗叡
Learn or Die

It's Ray. I do both backend and frontend, but more focus on backend. I like coding, and would like to see the whole picture of a product.