특수 메서드

매직 메서드는 특정 작업이 개체에 수행될 때 PHP의 기본 작업을 재정의하는 특수 메서드입니다.

주의 PHP에서는 모든 특수함수명이 __ 로 시작합니다. 문서화된 특수기능을 위한게 아니라면 함수명을 __ 로 시작하지 않을 것을 권장합니다.

다음 메서드 이름은 특수한 것으로 간주됩니다:__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() 그리고 __debugInfo().

경고 __construct(), __destruct()__clone()을 제외한 모든 매직 메서드는 public으로 선언해야 합니다. 그렇지 않으면 E_WARNING이 발생합니다. PHP 8.0.0 이전에는 매직 메소드 __sleep(), __wakeup(), __serialize(), __unserialize()__set_state()에 대해 진단이 내보내지지 않았습니다.

경고 매직 메소드의 정의에 유형 선언이 사용되는 경우 이 문서에서 설명하는 서명과 동일해야 합니다. 그렇지 않으면 치명적인 오류가 발생합니다. PHP 8.0.0 이전에는 진단이 내보내지지 않았습니다. 그러나 __construct()__destruct()는 반환 유형을 선언해서는 안 됩니다. 그렇지 않으면 치명적인 오류가 발생합니다.


__sleep()__wakeup()

public __sleep(): array

public __wakeup(): void

serialize()는 클래스에 마법 이름이 __sleep()인 함수가 있는지 확인합니다. 그렇다면 해당 함수는 직렬화 전에 실행됩니다. 객체를 정리할 수 있으며 직렬화되어야 하는 해당 객체의 모든 변수 이름이 포함된 배열을 반환해야 합니다. 메서드가 아무 것도 반환하지 않으면 null이 직렬화되고 E_NOTICE가 발행됩니다.

메모: __sleep()이 부모 클래스의 개인 속성 이름을 반환하는 것은 불가능합니다. 이렇게 하면 E_NOTICE 수준 오류가 발생합니다. 대신 __serialize()를 사용하십시오.

__sleep()의 의도된 용도는 보류 중인 데이터를 커밋하거나 유사한 정리 작업을 수행하는 것입니다. 또한 이 기능은 매우 큰 개체를 완전히 저장할 필요가 없는 경우에 유용합니다.

반대로, unserialize()는 매직 이름이 __wakeup()인 함수가 있는지 확인합니다. 존재하는 경우 이 함수는 개체가 가질 수 있는 모든 리소스를 재구성할 수 있습니다.

__wakeup()의 의도된 용도는 직렬화 중에 손실되었을 수 있는 데이터베이스 연결을 다시 설정하고 다른 재초기화 작업을 수행하는 것입니다.

예제 #1 Sleep과 wakeup

                  
<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;

    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __sleep()
    {
        return array('dsn', 'username', 'password');
    }

    public function __wakeup()
    {
        $this->connect();
    }
}?>
                  
                

__serialize()__unserialize()

public __serialize(): array

public __unserialize(array $data): void

serialize()는 클래스에 마법 이름이 __serialize()인 함수가 있는지 확인합니다. 그렇다면 해당 함수는 직렬화 전에 실행됩니다. 객체의 직렬화된 형태를 나타내는 키/값 쌍의 연관 배열을 생성하고 반환해야 합니다. 배열이 반환되지 않으면 TypeError가 발생합니다.

메모: __serialize()__sleep()이 모두 동일한 객체에 정의되어 있으면 __serialize()만 호출됩니다. __sleep()은 무시됩니다. 객체가 Serializable 인터페이스를 구현하는 경우 인터페이스의 serialize() 메서드는 무시되고 __serialize()가 대신 사용됩니다.

__serialize()의 의도된 용도는 객체의 직렬화 친화적인 임의 표현을 정의하는 것입니다. 배열의 요소는 개체의 속성에 해당할 수 있지만 필수는 아닙니다.

반대로, unserialize()는 매직 이름이 __unserialize()인 함수가 있는지 확인합니다. 존재하는 경우 이 함수는 __serialize()에서 반환된 복원된 배열을 전달합니다. 그런 다음 해당 배열에서 개체의 속성을 적절하게 복원할 수 있습니다.

메모: __unserialize()__wakeup()이 모두 동일한 객체에 정의된 경우 __unserialize()만 호출됩니다. __wakeup()은 무시됩니다.

메모: 이 기능은 PHP 7.4.0부터 사용할 수 있습니다.

예제 #2 직렬화 및 역직렬화

                  
<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;

    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }

    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }

    public function __serialize(): array
    {
        return [
          'dsn' => $this->dsn,
          'user' => $this->username,
          'pass' => $this->password,
        ];
    }

    public function __unserialize(array $data): void
    {
        $this->dsn = $data['dsn'];
        $this->username = $data['user'];
        $this->password = $data['pass'];

        $this->connect();
    }
}?>
                  
                

__toString()

public __toString(): string

__toString() 메서드는 클래스가 문자열로 변환될때의 동작을 결정하도록 해줍니다. 예를 들면, echo $obj;가 출력할 결과를 보면 됩니다.

경고 PHP 8.0.0부터 반환 값은 표준 PHP 유형 의미 체계를 따릅니다. 즉, 가능한 한 문자열로 강제 변환되고 엄격한 입력이 비활성화된 경우입니다.

PHP 8.0.0부터 __toString() 메서드를 포함하는 모든 클래스는 암시적으로 Stringable 인터페이스를 구현하므로 해당 인터페이스에 대한 유형 검사를 통과합니다. 어쨌든 인터페이스를 명시적으로 구현하는 것이 좋습니다.

PHP 7.4에서 반환된 값은 문자열이어야 합니다. 그렇지 않으면 오류가 발생합니다.

PHP 7.4.0 이전에는 반환된 값이 문자열이어야 합니다. 그렇지 않으면 치명적인 E_RECOVERABLE_ERROR가 발생합니다.

경고 PHP 7.4.0 이전에는 __toString() 메소드 내에서 예외를 던질 수 없었습니다. 그렇게 하면 치명적인 오류가 발생합니다.

예제 #3 간단한 예

                  
<?php
// Declare a simple class
class TestClass
{
    public $foo;

    public function __construct($foo)
    {
        $this->foo = $foo;
    }

    public function __toString()
    {
        return $this->foo;
    }
}

$class = new TestClass('Hello');
echo $class;
?>
                  
                

위의 예는 다음을 출력합니다.

Hello
                

__invoke()

__invoke( ...$values): mixed

__invoke() 메서드는 스크립트가 객체를 함수로 호출하려고 할 때 호출됩니다.

예제 #4 __invoke() 사용

                  
<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
                  
                

위의 예는 다음을 출력합니다.

int(5)
bool(true)
                

__set_state()

static __set_state(array $properties): object

static 메서드는 var_export()에서 내보낸 클래스에 대해 호출됩니다.

이 방법의 유일한 매개변수는 ['property' => value, ...] 형식으로 내보낸 속성을 포함하는 배열입니다.

예제 #5 __set_state() 사용

                  
<?php

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array)
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>
                  
                

위의 예는 다음을 출력합니다.

string(60) "A::__set_state(array(
   'var1' => 5,
   'var2' => 'foo',
))"
object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}
                

메모: 객체를 내보낼 때 var_export()__set_state()가 객체의 클래스에 의해 구현되었는지 여부를 확인하지 않으므로 __set_state()가 구현되지 않은 경우 객체를 다시 가져오면 오류 예외가 발생합니다. 특히 이것은 일부 내부 클래스에 영향을 줍니다. 클래스가 __set_state()를 구현하는 객체만 다시 가져올 것인지 확인하는 것은 프로그래머의 책임입니다.


__debugInfo()

__debugInfo(): array

이 메서드는 표시되어야 하는 속성을 가져오기 위해 개체를 덤프할 때 var_dump()에 의해 호출됩니다. 메서드가 개체에 정의되어 있지 않으면 모든 public, protected 및 private 속성이 표시됩니다.

예제 #6 __debugInfo() 사용

                  
<?php
class C {
    private $prop;

    public function __construct($val) {
        $this->prop = $val;
    }

    public function __debugInfo() {
        return [
            'propSquared' => $this->prop ** 2,
        ];
    }
}

var_dump(new C(42));
?>
                  
                

위의 예는 다음을 출력합니다.

object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}