클로저 – 07.클로저 리플렉션

리플렉션을 이용하면 클로저를 동적으로 생성하고 실행 중인 클로저의 정보를 분석할 수 있습니다.

클로저는 이름이 없지만, 일반적인 함수와 마찬가지로 클로저 객체에 대한 올바른 함수 포인터를 반환하기 때문에 리플렉션 기능을 활용할 수 있습니다.

메소드 또는 함수의 클로저를 생성할 수 있도록 ReflectionMethod 및 ReflectionFunction 클래스에 getClosure라는 메소드가 포함되어 있습니다.

getClosure 메소드를 이용하면 Closure 클래스의 fromCallable 메소드에서 처리할 수 없는 private, protected 메소드를 클로저로 변환할 수 있습니다.

동적 클로저 생성

리플렉션 API의 클로저 지원 기능을 활용하여 기존 함수 및 메소드를 동적으로 클로저로 변환하여 생성할 수 있습니다.

함수의 클로저 생성

ReflectionFunction 클래스를 사용하여 클로저로 변환하려는 함수의 인스턴스를 생성한 후, gerClosure 메소드로 해당 함수의 클로저를 생성합니다.

$closure는 hello 함수의 클로저입니다. var_dump로 확인한 $closure 클로저의 내부 정보를 보면 아래와 같습니다.

위 예제를 Closure 클래스의 fromCallable 메소드로 구현하면 아래와 같습니다.

메소드의 클로저 생성

메소드의 클로저를 생성하기 위해서는 우선 ReflectionClass 클래스의 gerMethod 메소드를 사용하여 클로저로 변환하려는 메소드의 인스턴스를 생성합니다.

ReflectionClass 클래스 대신 ReflectionMethod 클래스를 통해 해당 메소드의 동일한 인스턴스를 얻을 수 있습니다.

해당 메소드에 대한 클로저를 생성하기 위해서는 getClosure 메소드를 호출합니다. 비정적 메소드(non-static method)일 때는 getClosure의 단일 매개 변수로 Foo 클래스의 $this 포인터에 해당하는 인스턴스를 지정합니다.

위 예제는 Foo 클래스의 메소드 hello의 호출 가능한 객체인 클로저를 동적으로 생성합니다. 클로저를 호출하는 것은 해당 메소드를 직접 호출하는 것과 같습니다.

getClosure 메소드의 구문은 아래와 같으며, 실행하면 클로저를 동적으로 생성하여 반환합니다. 클로저 생성에 실패하여 오류가 발생하면 null을 반환합니다.

첫 번째 매개변수에는 해당 클래스의 인스턴스를 지정합니다. 정적 메소드의 경우에는 생략할 수 있습니다.

해당 메소드에 대한 클로저 $closure의 내부 정보를 var_dump로 확인하면 아래와 같습니다.

위 예제를 Closure 클래스의 fromCallable 메소드로 구현하면 아래와 같습니다.

정적 메소드의 클로저 생성

위 예제는 Foo 클래스의 정적 메소드 hello의 호출 가능한 객체인 클로저를 동적으로 생성합니다.

리플렉션 API 대신에 Closure 클래스 메소드인 fromCallable를 통해서도 정적 메소드를 클로저로 변환 시킬 수 있습니다.

private, protected 메소드의 클로저 생성

클로저로 변환하려는 메소드가 private, protected일 때는 fromCallable 메소드로는 할 수 없으며 리플렉션 API로만 변환할 수 있습니다.

private, protected 메소드를 Closure 클래스의 fromCallable 메소드로 변환하려고 하면 오류가 발생합니다.

  • Fatal error: Uncaught TypeError: Failed to create closure from callable: cannot access private method Foo::hello()

클로저 리플렉션

ReflectionFunction 클래스

리플렉션 API를 통해 클로저에 대한 많은 정보를 분석할 수 있습니다. 아래는 ReflectionFunction 클래스에 정의된 메소드들로 이 메소드들을 통해 클로저에 대한 내부 정보를 확인할 수 있습니다.

  • getClosure
  • invoke
  • invokeArgs
  • isDisabled
  • __toString
  • __clone
  • getClosureScopeClass
  • getClosureThis
  • getDocComment
  • getEndLine
  • getExtension
  • getExtensionName
  • getFileName
  • getName
  • getNamespaceName
  • getNumberOfParameters
  • getNumberOfRequiredParameters
  • getParameters
  • getReturnType
  • getShortName
  • getStartLine
  • getStaticVariables
  • hasReturnType
  • inNamespace
  • isClosure
  • isDeprecated
  • isGenerator
  • isInternal
  • isUserDefined
  • isVariadic
  • returnsReference

이 중에 getParameters 메소드를 호출하면 클로저에 정의된 매개변수에 대한 정보를 알 수 있습니다. 그러나 “use” 절의 정보는 포함되지 않습니다.

클로저에 대해 반환된 이름을 보면 항상 “{closure}”입니다.

ReflectionMethod 클래스

ReflectionFunction 클래스 대신에 ReflectionMethod 클래스를 사용해서 클로저에 대한 리플렉션 인스턴스를 생성할 수 있습니다.

클로저에 대해 반환된 이름을 보면 “{closure}”가 아니라 “__invoke”입니다. 나머지 클로저 정보는 ReflectionFunction 클래스에서의 경우와 동일합니다.

답글 남기기