Solidityでよく用いるmodifier修飾子について解説します。
そもそもmodifier修飾子とは?
modifier修飾子は、“関数の実行前に行いたい処理を定義した修飾子”です。
例えば、ある関数が実行される前に、“その関数を呼び出した人がコントラクトのオーナー自身かどうかをチェックしたい”といった場面で、そのチェック処理を記述したmodifierを作成し、そのmodifierを関数に修飾します。
関数実行前に行いたい処理をmodifierとして共通化することで、どの関数においても、modifierを修飾するだけでそれを事前処理できるという、事前処理を使い回せるメリットがあります。
modifier修飾子の書き方
modifier修飾子の書き方ですが、引数が無し/有りと、2つのパターンがあります。
それぞれ解説します。
引数が無い場合
// modifier修飾子の定義
modifier 修飾子名() {
処理
_;
}
// 関数にmodifierを修飾(この関数実行前にmodifierで定義した処理が呼び出される)
function 関数名() アクセス修飾子 modifier修飾子名 {
}
まず、各関数で共通して使用したい事前処理を、modifierとして定義します。
ここで重要なのが“_;(アンダースコアセミコロン)”です。
これは“処理を続行する”という意味の記述となりますので、modifierを修飾する関数の処理をそのまま続行したい場合には付けるようにしましょう。(modifierの用途にもよりますが基本的には付けるケースが多いと思います)
あとは、modifierで定義した処理を事前呼出したい関数に、そのmodifierを修飾します。
引数が有る場合
// modifier修飾子の定義
modifier 修飾子名(引数) {
処理
_;
}
// 関数にmodifierを修飾(この関数実行前にmodifierで定義した処理が呼び出される)
function 関数名() アクセス修飾子 modifier修飾子名(引数) {
}
まずmodifier側ですが、単に引数が付いただけで、先ほどの説明と同様です。
関数側も、引数を含めたmodifierで修飾します。
サンプルコード
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Test {
address owner;
constructor() {
owner = msg.sender;
}
// modifier修飾子の定義(引数無し)
modifier onlyOwner {
require (msg.sender == owner);
_;
}
// modifier修飾子の定義(引数有り)
modifier isAdult(uint age) {
require(age >= 18);
_;
}
// sayHi関数の実行前にmodifier(onlyOwner)の処理が実行される
function sayHi() public onlyOwner view returns(string memory) {
return "Hi Owner!";
}
uint myAge = 20;
// buyBeer関数の実行前にmodifier(isAdult)の処理が実行される
function buyBeer() public isAdult(myAge) view returns(string memory) {
return "Cheers!";
}
}
オーナーかどうかのチェックなど、どの関数でも呼び出したい処理がある場合、modifier修飾子として共通化しましょう。各関数ごとで毎回同じ処理を書くのはナンセンスですし、なによりコードの見通しや保守性が悪くなります。