Замыкания в PHP ... что именно они и когда нужно использовать?

Так что я программирую в красивой, современной объектно-ориентированной манере. Я регулярно использую различные аспекты ООП, которые реализует PHP, но мне интересно, когда мне нужно использовать замыкания. Есть ли там эксперты, которые могут пролить свет на то, когда было бы полезно реализовать закрытие?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
84
0
26 574
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Когда в будущем вам понадобится функция, которая будет выполнять задачу, которую вы определили сейчас.

Например, если вы читаете файл конфигурации, и один из параметров сообщает вам, что hash_method для вашего алгоритма - это multiply, а не square, вы можете создать замыкание, которое будет использоваться везде, где вам нужно что-то хешировать.

Замыкание может быть создано (например) в config_parser(); он создает функцию с именем do_hash_method(), используя локальные переменные config_parser() (из файла конфигурации). Каждый раз, когда вызывается do_hash_method(), он имеет доступ к переменным в локальной области видимости config_parser(), даже если он не вызывается в этой области.

Надеюсь, хороший гипотетический пример:

function config_parser()
{
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
        function do_hash_method($var)
        {
            // $hash_method is from the parent's local scope
            if ($hash_method == 'multiply')
                return $var * $var;
            else
                return $var ^ $var;
        }
    }
}


function hashme($val)
{
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
}

Я не могу просто скопировать этот пример и запустить его. Предпочитаю пример, который я могу просто запустить.

Kim Stacks 21.03.2013 12:59

Это плохой ответ. Это бессмысленное утверждение: «Когда в будущем вам понадобится функция, выполняющая задачу, которую вы выбрали сейчас».

Relaxing In Cyprus 11.09.2014 17:16

Помимо технических деталей, замыкания являются фундаментальной предпосылкой для стиля программирования, известного как функционально-ориентированное программирование. Замыкание примерно используется для тех же целей, что и объект в объектно-ориентированном программировании; Он связывает данные (переменные) вместе с некоторым кодом (функцией), который затем можно передать в другое место. Как таковые, они влияют на способ написания программ или - если вы не измените способ написания программ - они вообще не имеют никакого влияния.

В контексте PHP они немного странны, поскольку PHP уже сильно зависит от классовой объектно-ориентированной парадигмы, а также от более старой процедурной парадигмы. Обычно языки, у которых есть замыкания, имеют полную лексическую область видимости. Для обеспечения обратной совместимости PHP не получит этого, поэтому это означает, что замыкания здесь будут немного другими, чем на других языках. Думаю, нам еще предстоит увидеть, как именно они будут использоваться.

Мне нравится контекст, представленный в сообщении troelskn. Когда я хочу сделать что-то вроде примера Дэна Удея на PHP, я использую шаблон стратегии OO. На мой взгляд, это намного лучше, чем вводить новую глобальную функцию, поведение которой определяется во время выполнения.

http://en.wikipedia.org/wiki/Strategy_pattern

Вы также можете вызывать функции и методы, используя переменную, содержащую имя метода в PHP, и это здорово. так что другой подход к примеру Дэна будет примерно таким:

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }

        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

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

Ответ принят как подходящий

PHP будет поддерживать замыкания изначально в версии 5.3. Замыкание хорошо, когда вам нужна локальная функция, которая используется только для какой-то небольшой конкретной цели. RFC для закрытия дает хороший пример:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

Это позволяет вам определять функцию replacement локально внутри replace_spaces(), так что это не так:
1) Загромождение глобального пространства имен 2) Заставить людей через три года задуматься, почему существует функция, определенная глобально, которая используется только внутри одной другой функции

Он держит вещи в порядке. Обратите внимание, что у самой функции нет имени, она просто определена и назначена как ссылка на $replacement.

Но помните, вам нужно дождаться PHP 5.3 :)

Вы также можете получить доступ к переменным вне его области действия в замыкание с помощью ключевого слова use. Рассмотрим этот пример.

// Set a multiplier  
 $multiplier = 3;

// Create a list of numbers  
 $numbers = array(1,2,3,4);

// Use array_walk to iterate  
 // through the list and multiply  
 array_walk($numbers, function($number) use($multiplier){  
 echo $number * $multiplier;  
 }); 

Здесь дано отличное объяснение Что такое лямбды и замыкания в php

Это прекрасное объяснение. +1

David J Eddy 21.03.2013 17:22

Мне понравилось объяснение Почему, что вы будете использовать замыкания. Большинство людей этого не понимают. +1

Carrie Kendall 22.05.2013 19:57

Это объяснение анонимных функций, а не объяснение закрытий. Анонимные функции, как вы говорите, похожи на именованные функции, за исключением того, что они не являются глобальными. Замыкания, с другой стороны, представляют собой функции, содержащие свободные переменные с лексической областью видимости (объявленные с помощью "use"); т.е. они могут копировать и ссылаться на значения из области, в которой они объявлены, даже после того, как все остальное было собрано сборщиком мусора.

Warbo 28.06.2014 06:37

@Warbo Это правда; в то время я не особо ощутил разницу между анонимной функцией и закрытием. Замыкания действительно имеют смысл только после того, как вы изучили анонимные функции, но и по сей день Я все еще нахожу «объяснения» того, что такое замыкание (как и мое, от 7 лет назад ;-)), которые не объясняют его аспект области видимости.

dirtside 03.10.2015 07:16

Вот почему я сказал: проверьте JavaScript, где часто используются замыкания, но имейте в виду, что правила области видимости переменных в PHP разные.

Rolf 27.09.2017 20:37

Замыкание - это в основном функция, определение которой вы пишете в одном контексте, но запускаете в другом контексте. Javascript очень помог мне в их понимании, потому что они повсеместно используются в JavaScript.

В PHP они менее эффективны, чем в JavaScript, из-за различий в области видимости и доступности «глобальных» (или «внешних») переменных внутри функций. Тем не менее, начиная с PHP 5.4, замыкания могут обращаться к объекту $ this при запуске внутри объекта, что делает их намного более эффективными.

В этом суть замыканий, и этого должно быть достаточно, чтобы понять, что написано выше.

Это означает, что должна быть возможность написать где-нибудь определение функции и использовать переменную $ this внутри определения функции, затем присвоить определение функции переменной (другие дали примеры синтаксиса), а затем передать эту переменную объекту и вызывая его в контексте объекта, функция может затем обращаться к объекту и управлять им через $ this, как если бы это был просто еще один из его методов, хотя на самом деле он не определен в определении класса этого объекта, а где-то еще.

Если не очень понятно, то не волнуйтесь, станет ясно, как только вы начнете их использовать.

Честно говоря, мне это вообще непонятно даже мне, автору. В основном я говорю: чтобы узнать, что такое замыкание, проверьте их в JavaScript, но имейте в виду, что область видимости переменных в JavaScript и PHP различается.

Rolf 27.09.2017 20:34

Вот примеры закрытий в php

// Author: [email protected]
// Publish on: 2017-08-28

class users
{
    private $users = null;
    private $i = 5;

    function __construct(){
        // Get users from database
        $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
    }

    function displayUsers($callback){
        for($n=0; $n<=$this->i; $n++){
            echo  $callback($this->users[$n], $n);
        }
    }

    function showUsers($callback){
        return $callback($this->users);

    }

    function getUserByID($id, $callback){
        $user = isset($this->users[$id]) ? $this->users[$id] : null;
        return $callback($user);
    }

}

$u = new users();

$u->displayUsers(function($username, $userID){
    echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
    foreach($users as $user){
        echo strtoupper($user).' ';
    }

});

$x = $u->getUserByID(2, function($user){

    return "<h1>$user</h1>";
});

echo ($x);

Выход:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c

По сути, Closure - это внутренние функции, которые имеют доступ к внешним переменным и используются как функция обратного вызова для анонимной функции (функции, у которых нет имени).

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;

$param='captain' в функции sayhello() - это локальная переменная функции sayhello(). $param='ironman' выше sayhello() - глобальная переменная. Если вы хотите сделать в своем скрипте только одну переменную $ param, вы должны вызвать: global $param; в функции sayhello().

vlakov 23.04.2019 11:42

Закрытие:

У MDN есть лучшее объяснение IMO:

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function.

т.е. закрытие - это функция с доступом к переменным, которые находятся в родительской области. Замыкание позволяет нам удобно создавать функции на лету, поскольку в некоторых ситуациях функции нужны только в одном месте (обратные вызовы, вызываемые аргументы).

Пример:

$arr = [1,2,3,3];
$outersScopeNr = 2;

// The second arg in array_filter is a closure
// It would be inconvenient to have this function in global namespace
// The use keyword lets us access a variable in an outer scope
$newArr = array_filter($arr, function ($el) use ($outersScopeNr) {
    return $el === 3 || $el === $outersScopeNr;
});

var_dump($newArr);
// array (size=3)
//  1 => int 2
//  2 => int 3
//  3 => int 3

Другие вопросы по теме