수색…


클로저의 기본 사용법

클로저 는 PHP와 같은 익명의 함수입니다. 이름이없는 함수. 그것이 기술적으로 올바르지 않더라도 클로저의 동작은 몇 가지 추가 기능이있는 함수와 동일하게 유지됩니다.

클로저는 이름없이 함수를 선언함으로써 생성되는 Closure 클래스의 객체 일뿐입니다. 예 :

<?php

$myClosure = function() {
    echo 'Hello world!';
};

$myClosure(); // Shows "Hello world!"

$myClosureClosure 의 인스턴스이므로, $myClosure 를 사용하여 수행 할 수있는 작업을 인식 할 수 있습니다 (cf. http://fr2.php.net/manual/en/class.closure.php )

당신이 제공해야 할 때 당신은 폐쇄를 필요 고전적인 경우는 callable 인스턴스를 들어, 기능 에 usort .

다음은 배열이 각 사람의 형제 수에 따라 정렬되는 예제입니다.

<?php

$data = [
    [
        'name' => 'John',
        'nbrOfSiblings' => 2,
    ],
    [
        'name' => 'Stan',
        'nbrOfSiblings' => 1,
    ],
    [
        'name' => 'Tom',
        'nbrOfSiblings' => 3,
    ]
];

usort($data, function($e1, $e2) {
    if ($e1['nbrOfSiblings'] == $e2['nbrOfSiblings']) {
        return 0;
    }
    
    return $e1['nbrOfSiblings'] < $e2['nbrOfSiblings'] ? -1 : 1;
});

var_dump($data); // Will show Stan first, then John and finally Tom

외부 변수 사용하기

클로저 내부에서 특수 키워드 use 를 사용하여 외부 변수를 사용할 수 있습니다 . 예를 들면 :

<?php

$quantity = 1;

$calculator = function($number) use($quantity) {
    return $number + $quantity;
};

var_dump($calculator(2)); // Shows "3"

"동적"클로저를 작성하면 더 나아갈 수 있습니다. 추가하려는 수량에 따라 특정 계산기를 반환하는 함수를 만들 수 있습니다. 예 :

<?php

function createCalculator($quantity) {
    return function($number) use($quantity) {
        return $number + $quantity;
    };
}

$calculator1 = createCalculator(1);
$calculator2 = createCalculator(2);

var_dump($calculator1(2)); // Shows "3"
var_dump($calculator2(2)); // Shows "4"

기본 클로저 바인딩

이전에 볼 수 있듯이 클로저는 Closure 클래스의 인스턴스 일 뿐이며 여러 메서드가 호출 될 수 있습니다. 그 중 하나는 bindTo 이며, 주어진 클로저는 주어진 객체에 바인딩 된 새 객체를 반환합니다. 예 :

<?php

$myClosure = function() {
    echo $this->property;
};

class MyClass
{
    public $property;

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

$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance);

$myBoundClosure(); // Shows "Hello world!"

클로저 바인딩 및 범위

이 예제를 살펴 보겠습니다.

<?php

$myClosure = function() {
    echo $this->property;
};

class MyClass
{
    public $property;

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

$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance);

$myBoundClosure(); // Shows "Hello world!"

property 가시성을 protected 또는 private 로 변경하십시오. 이 속성에 대한 액세스 권한이 없다는 것을 나타내는 치명적인 오류가 발생합니다. 실제로 클로저가 객체에 묶여 있다고해도 클로저가 호출되는 범위는 해당 액세스를 필요로하는 범위가 아닙니다. 이것이 bindTo 의 두번째 인수가되는 bindTo .

속성이 private 경우 액세스 할 수있는 유일한 방법은 속성을 허용하는 범위에서 액세스하는 것입니다. 클래스의 범위. 바로 앞의 코드 예제에서 범위는 지정되지 않았으므로 클로저가 만들어 졌던 곳과 동일한 범위에서 클로저가 호출되었습니다. 그걸 바꾸자.

<?php

$myClosure = function() {
    echo $this->property;
};

class MyClass
{
    private $property; // $property is now private

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

$myInstance = new MyClass('Hello world!');
$myBoundClosure = $myClosure->bindTo($myInstance, MyClass::class);

$myBoundClosure(); // Shows "Hello world!"

방금 말했듯이이 두 번째 매개 변수가 사용되지 않으면 클로저는 클로저가 만들어진 위치와 동일한 컨텍스트에서 호출됩니다. 예를 들어, 객체 컨텍스트에서 호출되는 메소드의 클래스 내부에서 생성 된 클로저는 메소드의 범위와 동일합니다.

<?php

class MyClass
{
    private $property;

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

    public function getDisplayer()
      {
        return function() {
              echo $this->property;
        };
      }
}

$myInstance = new MyClass('Hello world!');

$displayer = $myInstance->getDisplayer();
$displayer(); // Shows "Hello world!"

하나의 호출에 대한 클로저 바인딩

PHP7 이후로 call 메소드 덕분에 하나의 호출에 대해서만 클로저를 바인딩 할 수 있습니다. 예를 들면 :

<?php

class MyClass
{
    private $property;

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

$myClosure = function() {
    echo $this->property;
};

$myInstance = new MyClass('Hello world!');

$myClosure->call($myInstance); // Shows "Hello world!"

bindTo 메서드와는 달리 걱정할 영역이 없습니다. 이 호출에 사용 된 범위는 $myInstance 의 속성에 액세스하거나 호출 할 때 사용되는 범위와 동일합니다.

관찰자 패턴 구현을 위해 클로저 사용

일반적으로 관찰자는 관찰 된 객체에 대한 작업이 발생할 때 특정 메소드가 호출되는 클래스입니다. 특정 상황에서 클로저는 관찰자 디자인 패턴을 구현하기에 충분할 수 있습니다.

이러한 구현의 자세한 예가 있습니다. 관찰자의 속성이 변경 될 때 관찰자에게 알리는 것이 목적 인 클래스를 먼저 선언합시다.

<?php

class ObservedStuff implements SplSubject
{
    protected $property;
    protected $observers = [];

    public function attach(SplObserver $observer)
    {
        $this->observers[] = $observer;
        return $this;
    }

    public function detach(SplObserver $observer)
    {
        if (false !== $key = array_search($observer, $this->observers, true)) {
            unset($this->observers[$key]);
        }
    }

    public function notify()
    {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    public function getProperty()
    {
        return $this->property;
    }

    public function setProperty($property)
    {
        $this->property = $property;
        $this->notify();
    }
}

그런 다음 다른 관찰자를 대표 할 클래스를 선언합시다.

<?php

class NamedObserver implements SplObserver
{
    protected $name;
    protected $closure;

    public function __construct(Closure $closure, $name)
    {
        $this->closure = $closure->bindTo($this, $this);
        $this->name = $name;
    }

    public function update(SplSubject $subject)
    {
        $closure = $this->closure;
        $closure($subject);
    }
}

마침내 이것을 시험해 봅시다.

<?php

$o = new ObservedStuff;

$observer1 = function(SplSubject $subject) {
    echo $this->name, ' has been notified! New property value: ', $subject->getProperty(), "\n";
};

$observer2 = function(SplSubject $subject) {
    echo $this->name, ' has been notified! New property value: ', $subject->getProperty(), "\n";
};

$o->attach(new NamedObserver($observer1, 'Observer1'))
  ->attach(new NamedObserver($observer2, 'Observer2'));

$o->setProperty('Hello world!');
// Shows:
// Observer1 has been notified! New property value: Hello world!
// Observer2 has been notified! New property value: Hello world!

이 예제는 관찰자가 동일한 성격을 공유하기 때문에 작동합니다 (둘 다 "명명 된 관찰자"임).



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow