0x00 서문
클로저란 생성 시 주변 상태를 캡슐화하는 함수를 말합니다. 클로저가 위치한 환경이 더 이상 존재하지 않더라도 클로저에 캡슐화된 상태는 여전히 존재합니다.
PHP의 모든 클로저는 Clorse 클래스에 의해 인스턴스화되는 객체입니다. 즉, 클로저는 다른 PHP 객체와 다르지 않습니다. 객체에는 해당 메소드와 속성이 있어야 합니다. 이 기사에서는 PHP에서 클로저의 기본 사용법과 Clorse 클래스 메소드의 역할을 요약합니다. [추천: PHP 비디오 튜토리얼]
0x01 클로저의 기본 사용법
클로저의 가장 기본적인 사용법을 살펴보겠습니다:
<?php $hello = function ($word) { return 'hello ' . $word; }; echo $hello('world'); // 输出 hello world
이 코드의 가장 직관적인 느낌은 다음에 함수를 할당하는 것입니다. $hello 변수를 선택한 다음 $hello를 통해 직접 호출합니다. 하지만 이 클로저는 상위 범위에서 변수를 상속하지 않습니다(즉, 주변 상태를 캡슐화합니다). use 키워드를 통해 클로저의 상위 범위에서 변수를 상속할 수 있습니다. 예는 다음과 같습니다:
<?php $name = 'panda'; $hello = function () use ($name) { return 'hello ' . $name; }; echo $hello(); // 输出 hello panda
PHP 7.1부터 사용은 superglobals, $this 또는 매개변수와 동일한 이름을 갖는 변수를 전달할 수 없습니다.
또한 use 키워드를 사용하면 상위 범위의 변수가 값으로 클로저에 전달됩니다. 즉, 클로저가 생성되면 외부 변수가 수정되더라도 클로저에 전달된 값에는 영향을 미치지 않습니다. 폐쇄는 여전히 존재합니다). 예는 다음과 같습니다:
<?php $name = 'panda'; $hello = function () use ($name) { return 'hello ' . $name; }; $name = 'cat'; echo $hello(); // 输出 hello panda
변수에 대한 참조를 전달하면 클로저가 외부 변수의 값을 수정할 수 있습니다. 예는 다음과 같습니다.
<?php $name = 'panda'; $changeName = function () use (&$name) { $name = 'cat'; }; $changeName(); echo $name; // 输出 cat
참고: PHP에서 객체를 전달할 때 기본값은 전달입니다. 참조로 사용하므로 클로저 내에서 사용하여 전달된 객체를 조작할 때는 특별한 주의가 필요합니다. 예는 다음과 같습니다:
<?php class Dog { public $name = 'Wang Cai'; } $dog = new Dog(); $changeName = function () use ($dog) { $dog->name = 'Lai Fu'; }; $changeName(); echo $dog->name; // 输出 Lai Fu
0x02 클로저 클래스
클로저가 단지 클로저 클래스 객체임을 증명
<?php $clourse = function () { echo 'hello clourse'; }; if (is_object($clourse)) { echo get_class($clourse); } // 输出 Closure
위 코드는 클로저가 단지 일반적인 클로저 클래스 객체임을 증명하는 Closure를 출력합니다.
Clouse 클래스 요약
PHP 공식 매뉴얼에서 클로저 클래스에 대한 관련 정보를 확인할 수 있습니다. 다음은 PhpStorm의 로컬 문서에서 본 Clouse 클래스의 요약입니다.
/** * Class used to represent anonymous functions. * <p>Anonymous functions, implemented in PHP 5.3, yield objects of this type. * This fact used to be considered an implementation detail, but it can now be relied upon. * Starting with PHP 5.4, this class has methods that allow further control of the anonymous function after it has been created. * <p>Besides the methods listed here, this class also has an __invoke method. * This is for consistency with other classes that implement calling magic, as this method is not used for calling the function. * @link http://www.php.net/manual/en/class.closure.php */ final class Closure { /** * This method exists only to disallow instantiation of the Closure class. * Objects of this class are created in the fashion described on the anonymous functions page. * @link http://www.php.net/manual/en/closure.construct.php */ private function __construct() { } /** * This is for consistency with other classes that implement calling magic, * as this method is not used for calling the function. * @param mixed $_ [optional] * @return mixed * @link http://www.php.net/manual/en/class.closure.php */ public function __invoke(...$_) { } /** * Duplicates the closure with a new bound object and class scope * @link http://www.php.net/manual/en/closure.bindto.php * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope The class scope to which associate the closure is to be associated, or 'static' to keep the current one. * If an object is given, the type of the object will be used instead. * This determines the visibility of protected and private methods of the bound object. * @return Closure Returns the newly created Closure object or FALSE on failure */ function bindTo($newthis, $newscope = 'static') { } /** * This method is a static version of Closure::bindTo(). * See the documentation of that method for more information. * @static * @link http://www.php.net/manual/en/closure.bind.php * @param Closure $closure The anonymous functions to bind. * @param object $newthis The object to which the given anonymous function should be bound, or NULL for the closure to be unbound. * @param mixed $newscope The class scope to which associate the closure is to be associated, or 'static' to keep the current one. * If an object is given, the type of the object will be used instead. * This determines the visibility of protected and private methods of the bound object. * @return Closure Returns the newly created Closure object or FALSE on failure */ static function bind(Closure $closure, $newthis, $newscope = 'static') { } /** * Temporarily binds the closure to newthis, and calls it with any given parameters. * @link http://php.net/manual/en/closure.call.php * @param object $newThis The object to bind the closure to for the duration of the call. * @param mixed $parameters [optional] Zero or more parameters, which will be given as parameters to the closure. * @return mixed * @since 7.0 */ function call ($newThis, ...$parameters) {} /** * @param callable $callable * @return Closure * @since 7.1 */ public static function fromCallable (callable $callable) {} }
우선, Clorse 클래스는 상속될 수 없다는 것을 의미합니다. 둘째, 생성자 __construct는 private으로 설정됩니다. 이는 클로저 객체가 new 키워드를 통해 인스턴스화될 수 없음을 의미합니다. 클로저만 구문 함수 (...) use(...) {...}를 통해서만 인스턴스화할 수 있는지 확인하십시오.
클로저를 함수로 실행할 수 있는 이유는 무엇인가요?
위 클래스 요약을 보면 Clorse 클래스가 __invoke 메소드를 구현한 것을 알 수 있습니다. 해당 메소드는 공식 PHP 매뉴얼에 다음과 같이 설명되어 있습니다.
함수를 호출하여 객체를 호출하려고 하면 __invoke() 메소드 will이 자동으로 호출됩니다.
이것이 클로저가 함수로 실행될 수 있는 이유입니다.
지정된 $this 객체와 클래스 범위를 바인딩합니다
클로저 라우팅 사용을 허용하는 프레임워크(예: Slim)에서 다음과 같은 내용을 볼 수 있습니다.
$app->get('/test', function () { echo $this->request->getMethod(); });
이 클로저에서 $를 실제로 사용할 수 있나요? $this가 가리키는 객체는 무엇인가요?
$this를 클래스 범위에 바인딩하는 기능은 바인딩To 및 바인딩 메서드를 통해 수행할 수 있습니다. 예는 다음과 같습니다.
<?php class Pandas { public $num = 1; } $pandas = new Pandas(); $add = function () { echo ++$this->num . PHP_EOL; }; $newAdd1 = $add->bindTo($pandas); $newAdd1(); // 输出 2 $newAdd2 = Closure::bind($add, $pandas); $newAdd2(); // 输出 3
위 예는 지정된 개체를 클로저의 $this에 바인딩하지만 우리는 그렇지 않습니다. 클래스 범위를 지정합니다. 따라서 Pandas 클래스의 $num 속성을 protected 또는 private으로 다시 작성하면 치명적인 오류가 발생합니다!
Fatal error: Uncaught Error: Cannot access protected property Pandas::$num
바인딩된 개체의 비공개 속성이나 메서드에 액세스해야 하는 경우 클래스 범위를 지정해야 합니다. 예는 다음과 같습니다.
<?php class Pandas { protected $num = 1; } $pandas = new Pandas(); $add = function () { echo ++$this->num . PHP_EOL; }; $newAdd1 = $add->bindTo($pandas, $pandas); $newAdd1(); // 输出 2 $newAdd2 = Closure::bind($add, $pandas, 'Pandas'); $newAdd2(); // 输出 3
여기서 우리는 binTo 및 바인딩 메서드 모두 $newscope를 지정하는 것을 볼 수 있습니다. $newscope 매개변수의 기본값은 static입니다. 즉, 클래스 범위는 변경되지 않습니다. $newscope 매개변수는 클래스 이름이나 객체를 받아 클로저의 클래스 범위를 지정된 클래스 범위로 변경합니다. 이때 클로저에서 Pandas 클래스의 $num 속성에 접근할 수 있습니다.
$this 개체와 클래스 범위를 한 번에 바인딩하고 실행합니다(PHP7).
bindTo 및 바인딩 메서드는 새 개체 및 클래스 범위 패키지가 지정될 때마다 원래 클로저를 복사하고 새 클로저를 반환해야 합니다. 바인딩된 개체를 여러 번 수정해야 하는 경우 번거롭기 때문에 PHP7은 클로저를 개체(클래스 범위도 해당 개체가 속한 개체로 수정됨)에 일시적으로 바인딩하고 실행할 수 있는 새로운 메서드 호출을 제공합니다.
<?php class Pandas { protected $num = 1; } $pandas = new Pandas(); $add = function ($num) { $this->num += $num; echo $this->num . PHP_EOL; }; $add->call($pandas, 5); // 输出 6
Callable to closure (PHP7.1)
PHP7.1에서 Closure 클래스에는 호출 가능 유형 값을 클로저로 변환할 수 있는 fromCallable 메서드가 있습니다.
<?php class Foo { protected $num = 1; public static function hello(string $bar) { echo 'hello ' . $bar; } } $hello = Closure::fromCallable(['Foo', 'hello']); $hello('world');
이런 작성 방법이 꽤 멋지군요. 결국 클로저를 통해 호출하는 것이 call_user_func 함수를 사용하는 것보다 훨씬 더 재미있습니다.
0x03 요약
자세한 내용은 Closure 클래스 및 익명 함수를 참조하세요. PHP 공식 매뉴얼의 Closure 클래스 중국어 버전은 업데이트되지 않았기 때문에 call 및 fromCallable 메서드에 대한 내용이 없습니다. . 영문판(ㄒoㄒ)을 읽어보시길 권합니다.
위 내용은 PHP 클로저 및 Course 클래스 메소드의 기능 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!