
함수의 동작을 변경할 수 있는 기능으로, 함수 전/후에 특정 행동을 넣어줄 수 있다.
정의할 때는 function @@ 대신 modifier @@으로 작성하고,
클래스 상속이나 인터페이스 구현처럼 함수 옆에 표시하여 사용한다.
본문에서 함수의 실행 위치를 지정할 수 있다.
참고 : solidity - Modifier(함수변경자)
링크 : https://docs.soliditylang.org/en/latest/contracts.html

- Modifier는 함수의 동작을 선언적(declarative)으로 바꿀 수 있다.
선언형 프로그래밍 글 참고 : 명령형 프로그래밍 VS 선언형 프로그래밍
- 상속이 가능한 속성이고, 오버라이딩할 수 있지만 조건이 있음
오버라이딩의 조건은 원문에 링크로 걸려있는 Modifier Overriding 참고
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;
contract owned {
constructor() { owner = payable(msg.sender); }
address payable owner;
// This contract only defines a modifier but does not use
// it: it will be used in derived contracts.
// The function body is inserted where the special symbol
// `_;` in the definition of a modifier appears.
// This means that if the owner calls this function, the
// function is executed and otherwise, an exception is
// thrown.
modifier onlyOwner {
require(
msg.sender == owner,
"Only owner can call this function."
);
_;
}
}
contract priced {
// Modifiers can receive arguments:
modifier costs(uint price) {
if (msg.value >= price) {
_;
}
}
}
contract Register is priced, owned {
mapping(address => bool) registeredAddresses;
uint price;
constructor(uint initialPrice) { price = initialPrice; }
// It is important to also provide the
// `payable` keyword here, otherwise the function will
// automatically reject all Ether sent to it.
function register() public payable costs(price) {
registeredAddresses[msg.sender] = true;
}
// This contract inherits the `onlyOwner` modifier from
// the `owned` contract. As a result, calls to `changePrice` will
// only take effect if they are made by the stored owner.
function changePrice(uint price_) public onlyOwner {
price = price_;
}
}
contract Mutex {
bool locked;
modifier noReentrancy() {
require(
!locked,
"Reentrant call."
);
locked = true;
_;
locked = false;
}
/// This function is protected by a mutex, which means that
/// reentrant calls from within `msg.sender.call` cannot call `f` again.
/// The `return 7` statement assigns 7 to the return value but still
/// executes the statement `locked = false` in the modifier.
function f() public noReentrancy returns (uint) {
(bool success,) = msg.sender.call("");
require(success);
return 7;
}
}
- 여러 modifier를 한 함수에 동시에 적용할 수 있다
띄어쓰기로 구분하고, 작성한 순서대로 실행함
- modifier가 함수의 값을 쓰려면 명시적으로 전달해야 한다
적용되는 함수의 인자에 자동 접근, 변경 불가능
modifier costs(uint price) --> costs(price) 처럼 사용
- 수정자가 적용되는 함수를 언제 실행할지 지정해야 한다
언더바( _ )로 지정할 수 있으며, 이 언더바는 변수 이름의 앞이나 뒤에 밑줄을 사용하는 것과는 다르다
(* solidity 버전에 따라 표현이 조금 다르다. => 0.4.0 이하는 ; 없이_사용 )
예시:contract priced { // Modifiers can receive arguments: modifier costs(uint price) { if (msg.value >= price) { _; // 이 modifier를 사용하는 함수 본문의 실행위치 지정 } } } . . . // 수정자가 적용되는 함수 = register() function register() public payable costs(price) { registeredAddresses[msg.sender] = true; }위의 경우
if (msg.value >= price)가 true
→_;=registeredAddresses[msg.sender] = true;
의 순서대로 실행된다
- modifier나 함수 내부에서 return을 쓰면, 해당 modifier나 함수만 종료된다.
만약 아래와 같은 함수라면 (임의로 작성한 코드, 공식문서 아님)modifier first() { _; // 코드a } modifier second() { _; // 코드b } function test() public first second { return; }(test 사용 상황 시 코드 흐름)
→first(modifier) 실행 →\_;→ 함수본문 실행
→ (*여러 modifier 적용, 띄어쓰기로 구분) 그 다음 modifier 실행
→second(modifier) 실행 →\_;→ 함수본문 실행
→return;(해당 함수만 종료)
→ second 마저 실행 (함수본문 내용 끝남) →코드b→ second 끝
→ first 마저 실행 (함수본문 내용 끝남) →코드a→ first 끝
→ 종료
- modifier 안에서 return;을 써도 함수 리턴값에는 영향을 주지 않는다.
하지만 modifier가 아예 함수 본문을 실행하지 않으면 함수의 리턴값은 기본값으로 반환된다.예시 - (임의로 작성한 코드, 공식문서 아님)
contract Example { modifier skipIfZero(uint x) { if (x == 0) { return; } _; // 함수 본문 실행 } function test(uint x) public pure skipIfZero(x) returns (uint) { return 42; } }→
skipIfZero(modifier) 실행 하면case1)
<x=0>
→return;
→ (_;를 건너뛰어서 함수본문을 실행하지 않음.)
= test의 return 값=0 (uint의 기본값)case2)
<x=3>
→ (_;부분에 도달, 함수본문을 실행)
→return 42;
= test의 return 값=42
- modifier 안에 _(함수실행)를 여러 번 쓸 수도 있다.
다만, 함수는 최종 기호(마지막으로 실행한 함수 본문)의 반환값을 반환한다.
- modifier에 인자를 전달할 때 어떤 표현식이든 넣고 쓸 수 있다.
따라서 함수에서 볼 수 있는 심볼은 modifier 내부에서도 볼 수 있다.
하지만 반대는 불가능함. (= modifier 내부에서 추가된 심볼은 함수가 못봄)
java를 배우면서도 modifier를 봤는데, 서로 용어의 쓰임이 다른 것 같아 정리해봤다
접근 제어자 (Access Modifiers) : public, protected, default, private
그 외 : static, final, abstract...
java에서는 public, private.. 이 modifier로 불리는 반면,
solidity에서는 public, priavate, external, internal 을 Scope 혹은 Visibility 로 불리는 것 같다.
( 참고 : [Solidity] Scope와 Visibility (Public, Private, External, Internal) )
근데 또 java에서도 scope는 다른 의미로 쓰이는 것 같다...?
- [Java] 지역 변수와 스코프(Scope)
- Java에서 이해하는 Scope
아마도 이렇게 구분할 수 있는 것 같다..
(java scope 설명이 맞는지 모르겠다)
| modifier | scope | |
|---|---|---|
| Java | public, private.. | 변수나 메소드 등의 접근 범위 |
| Solidity | 함수의 동작을 변경할 수 있는 기능 | public, priavate, external... |