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


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

6 65

6 ответов:

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

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

это позволяет определить

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

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

закрытие может быть создано в (например)config_parser(); он создает функцию do_hash_method() использование переменных local to 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)
}

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

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

Мне нравится контекст, предоставленный сообщением трольскна. Когда я хочу сделать что-то вроде примера Дэна Удея в 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

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

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

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

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

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

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

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

// Author: HishamDalal@gamil.com
// 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