# Замыкания в PHP

В php замыкания это объекты класса `Сlosure`, создаются при присвоении функции переменной или передачи анонимной функции, и может замыкать в себе значения переменных.

{% hint style="info" %}
В отличии от JS, функции в PHP не имеют доступа к значениям переменных из родительской области видимости автоматически, его можно получить через `use()`
{% endhint %}

Если при создании замыкания мы наследуем переменные из глобальной области через `use()`, то значение этих переменных будет хранится в замыкании, и будут соответствовать значениям переменных на момент определения функции, а не на момент её вызова.<br>

```php
$message = 'привет';

// Наследуем $message
$example = function () use ($message) {
    var_dump($message);
};
$example(); // "Привет"

// Значение унаследованной переменной задано там, где функция определена,
// но не там, где вызвана (в отличии от JS)
$message = 'мир';
$example(); // "Привет"
```

Так же созданное замыкание может хранить в себе значение переменной...

```php
function getCounter(){
    $count = 0;

    return function () use (&$count){ // наследуем по ссылке $count из родительской области видимости
        return $count++;
    };
}

$counter = getCounter(); // получаем замыкание которое хранит в себе значение переменной $count, которая находится в его "замкнутой" родительской области видимости

var_dump($counter);

echo $counter(); // 0
echo $counter(); // 1
echo $counter(); // 2

var_dump($counter);
```

### Замыкания в PHP в ООП (**Автоматическое связывание `$this`**)

В ООП, когда мы записываем метод обьекта в функцию (например [`$closure = $gizmo->getName(...)`](#user-content-fn-1)[^1]), то получаем замыкание, которое хранит контекст и значение $this соответствует объекту из которого мы записывали метод.\
Но его можно привязать к другому объекту функцией bindTo();

```php
class Person {
    public $name;

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

    public function getName(){
        return $this->name;
    }

    public function runClosure($closure){
        // возвращаем результат функции переданной в качестве аргумента
        return $closure();
    }
}

$gizmo = new Person('Gizmo','mr.');
$freeman = new Person('Freeman', 'dr.');

// записываем метод getName() в переменную (именно объект Closure с функцией внутри, а не результат функции)
$closure = $gizmo->getName(...);

// вызывем замыкание внутри объекта $freeman, но оно вернёт "Gizmo" так как само замыкание хранит $this которое ссылается на свой объект, в данном случае $gizmo
echo $freeman->runClosure($closure);

// связываем замыкание с объектом $freeman
$closure = $closure->bindTo($freeman);

// и теперь замыкание выдаст "Freeman"
echo $freeman->runClosure($closure);
```

[^1]: С помощью синтаксиса funcName(...) мы получаем не результат выполнения функции, а саму функцию в виде замыкания (объекта класса Closure)
