Замыкания в php

    Не секрет, что в PHP 5.3 был введен ряд интересных новшеств. Разной степени полезности и скандальности. Возможно даже, что выпуск PHP 5.3 — хорошо спланированный PR-ход: самый большой список изменений за последние пять лет, оператор goto (sic!), пространства имен (namespaces) с синтаксисом «не как у всех», позднее статическое связывание (late static binding), более-менее честные анонимные (лямбда) функции (lambda functions), замыкания (closures).

    О последних я и хочу рассказать. Справедливости ради хочу добавить, что в PHP 5.3 введено и много другого функционала, который делает этот релиз примечательным: модули Intl (интернационализация), Phar (PHP-архивы, наподобие JAR для JAVA), mysqlnd (новый драйвер для mysql), улучшения в SPL, общее увеличение производительности до 10% и много еще чего.

    Замыкания (closures) и лямбда-функции (lambda functions) — нововведения PHP 5.3, вообще говоря, не являются передовым рубежом современных технологий. Удивительно, но и то и другое появилось в функциональном языке программирования LISP в конце 50-х, и было допилено напильником до состояния близкого к современному в 70-х годах. Таким образом, PHP подотстал с грамотной реализацией лет на 40.

    Замыкания, если верить википедии — это процедуры, которые ссылаются на свободные переменные в своём лексическом контексте. Академически строго, но если бы я не знал о чем речь, никогда бы не понял из этого определения.

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

    //*** Пример 1j ***
    function outer(x) //Определение внешней функции
    {
            var y=2; //Локальная переменная внешней функции
            function inner(a) //Определение внутренней функции
            {
                    var b=4; //Локальная переменная внутренней функции
                    /* А дальше складываются переменные внутренней и
                     * внешней функций, как будто все они локальные
                     * переменные внутренней функции
                     */
                    var res=x+y+a+b;
                    alert(res); //Результат 10 в нашем примере.
            }
            inner(3); //Вызов внутренней функции
    }
    outer(1); //Вызов внешней функции, а она вызовет внутреннюю.
    


    Итак, функция inner, без какого-то специального объявления свободно использует переменные внешней функции outer. Но это еще не замыкание.

    Во многих языках программирования функция (имеется в виду не результат выполнения функции, а сама функция как исполняемый код, указатель на функцию), это некий объект особого типа. Как любой другой объект (строка, число, массив), функция может быть присвоена переменной, передана в другую функцию в качестве параметра и возвращена как результат выполнения другой функции. С этим связана и еще одна важная вещь: Функции при ее определении, можно не присваивать имени, а присвоить эту функцию переменной и вызывать ее через эту переменную. Сама же функция не имеет собственного имени, и поэтому остается "анонимной". Такие функции называют так же лямбда функциями.

    // *** Пример 2j ***
    adder=function(a,b) //У функции нет имени, но она присваивается переменной
    {
            return a+b; //вернуть сумму
    }
    subber=function(a,b) { return a-b; } //То же самое, просто в одну строку
    /*
     * Прошу обратить внимание - тут переменным adder и subber присваивается не
     * результат вычисления суммы или разности каких то чисел, а, грубо говоря,
     * сам код функции. Т.е. в переменной adder и subber сейчас не число, а код,
     * который можно вызвать так: x=adder(1,3); и вот x уже будет числом.
     */
    function performAction(action, a, b) //Обычная функция с именем performAction
    {
            var result=action(a,b); //предполагается что параметр action - это функция
            return result;
    }
    function makeDivider() //Обычная функция с именем makeDivider
    {
            return function (a,b) //Возвращает безымянную функцию
            {
                    return a/b;
            }
    }
    r1=adder(1,2); //Вызываем безымянную функцию через переменную. r1=1+2;
    r2=performAction(subber,6,4); //Передаем функцию в другую функцию. r2=6-4;
    r3=performAction(function(a,b) {return a*b;} ,5,6); //То же самое прямо на лету. r3=5*6;
    divider=makeDivider(); //Вызываем функцию, которая возвращает функцию, сохраняем результат
    r4=divider(16,4); //Вызываем функцию возвращенную функцией через переменную: r4=16/4;
    r5=makeDivider()(32,16);//То же самое, но без промежуточной переменной: r5=32/16;
    alert([r1,r2,r3,r4,r5]); //3,2,30,4,2
    


    Если предыдущие примеры более-менее ясны, то замыкания тоже будут понятны, потому что являются, по сути, комбинацией описанных выше двух принципов:
    • Анонимная функция определенная внутри любой другой функции, имеет доступ к переменным родителя.
    • Если родительская функция вернет дочернюю функцию в качестве результата своей работы, переменные родительской функции останутся доступны в дочерней, несмотря на то, что родительская уже отработала и ее локальные переменные должны удалиться.

    Т.е. вложенная функция как бы замыкает на себя переменные из родительских скопов, не давая им уничтожиться. А вот и полезный пример на Javascript:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Closure test</title>
    </head>
    <body>
    <a href="#" id="link1">Нажми</a> <a href="#" id="link2">И меня нажми</a>
    <div id="hide1">Скрой меня скорее</div>
    <div id="hide2">И меня тоже скрой</div>
    
    <script>
    // *** Пример 3j ***
    function getHider(id) //Передаем id элемента который надо скрыть
    {
            return function()
            {
                    document.getElementById(id).style.display='none';
                    return false;
            }
            /*
             * У возвращаемой функции нет параметров, но параметр id родительской
             * функции как бы вшивается в нее перед возвратом ее в качестве результата.
             * Вызывая getHider с разными параметрами
             * можно в результате ее работы получить ряд очень похожих функций,
             * каждая из которых умеет скрывать один элемент.
             */
    }
    document.getElementById('link1').onclick=getHider('hide1');
    document.getElementById('link2').onclick=getHider('hide2');
    /*
     * Здесь в качестве обработчика события onclick двух ссылок мы
     * назначаем не функцию getHider, а результат ее работы, а им
     * является функция, внутрь которой вшит id='hide1' в первом случае
     * и id='hide2' во втором. Таким образом, функция назначенная
     * обработчиком внутри себя знает, какой элемент ей надо скрыть
     */
    </script>
    
    </body>
    </html>
    


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

    Вернемся к PHP. В нем все не так красиво как в Javascript. Во-первых, для того чтобы функция могла использовать переменные родительской функции, надо это явно указать в ее определении (это следует из идеологии языка), во-вторых работает это только с анонимными функциями и работает это все только с PHP 5.3. Пример 1j в исполнении PHP будет выглядеть как-то так:

    // *** Пример 1p ***
    function outer($x) //Определение внешней функции
    {
            $y=2; //Локальная переменная внешней функции
            $inner=function ($a) use ($x, $y) //Определение внутренней функции
            {
                    $b=4; //Локальная переменная внутренней функции
                    /* А дальше складываются переменные внутренней и
                     * внешней функций, как будто все они локальные
                     * переменные внутренней функции
                     */
                    $res=$x+$y+$a+$b;
                    echo $res; //Результат 10 в нашем примере.
            };
            $inner(3); //Вызов внутренней функции
    }
    outer(1);
    


    А наш пример 2j как то так:

    // *** Пример 2p ***
    $adder=function($a,$b) //У функции нет имени, но она присваивается переменной
    {
            return $a+$b; //вернуть сумму
    };
    
    $subber=function($a,$b) { return $a-$b; }; //То же самое, просто в одну строку
    
    function performAction($action, $a, $b) //Обычная функция с именем performAction
    {
            $result=$action($a,$b); //предполагается что параметр action - это функция
            return $result;
    }
    
    function makeDivider() //Обычная функция с именем makeDivider
    {
            return function ($a,$b) //Возвращает безымянную функцию
            {
                    return $a/$b;
            };
    }
    
    $r1=$adder(1,2); //Вызываем безымянную функцию через переменную. r1=1+2;
    $r2=performAction($subber,6,4); //Передаем функцию в другую функцию. r2=6-4;
    $r3=performAction(function($a,$b) {return $a*$b;} ,5,6); //То же самое прямо на лету. r3=5*6;
    $divider=makeDivider(); //Вызываем функцию, которая возвращает функцию, сохраняем результат
    $r4=$divider(16,4); //Вызываем функцию возвращенную функцией через переменную: r4=16/4;
    //А такие вещи как в r5 в PHP вообще не прокатывают.
    //$r5=makeDivider()(32,16);//То же самое, но без промежуточной переменной: r5=32/16;
    $r5='php fail';
    echo "$r1,$r2,$r3,$r4,$r5"; //3,2,30,4,php fail
    


    Анонимные функции в PHP позволяют упростить и сделать нагляднее применение различных встроенных функций использующих callback, например:

    //По старинке:
    function cmp($a, $b)
    {
        return($a > $b);
    }
    //тут еще всякий код
    uasort($array, 'cmp'); //А тут использование этой функции
    
    //По новому:
    uasort($array, function($a, $b) { return($a > $b);});
    


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

    Может показаться, что анонимные функции уже были в предыдущих версиях PHP. Разве create_function, это не оно — то самое? И да, и нет. create_function при каждом вызове создает новую настоящую именованную функцию в глобальном пространстве имен(sic!), но ее имя начинается с \0 (нулевого байта) и поэтому не может вступить в конфликт с обычными функциями. Но разве можно назвать такую функцию действительно анонимной? Кстати, create_function возвращает строку с именем этой «анонимной» функции. В остальном, использование действительно похоже на использование анонимных функций в PHP 5.3:

    //Новый старый лад, работает даже в PHP 4!:
    uasort($array, create_function('$a, $b','return $a > $b;'));
    


    Зачем нужны замыкания в PHP я понимаю слабо. Для простого сохранения состояния функции между вызовами? Например так:

    function getModernIncrementer()
    {
        $x=0;
        return function() use(&$x) //Обязательно указать передачу по ссылке!
        {
           return $x++;
        };
    }
    $incrementer2=getModernIncrementer();
    echo $incrementer2(), $incrementer2(), $incrementer2();//012
    


    Но для этого существует static переменные. Их использование проще, удобнее и требует меньше кода:

    function incrementer()
    {
        static $x=0;
        return $x++;
    }
    echo incrementer(),incrementer(),incrementer(); //012
    


    Для сложного сохранения состояния между вызовами существует ООП. Кстати, анонимные функции в PHP 5.3 все же не совсем честные функции! На поверку эта функция оказывается… оказывается… Внимание, фокус:

    var_dump(function(){return 1;}); // object(Closure)#1 (0) { }
    


    Функция оказывается объектом класса Closure — и вот оно это ваше ООП. А чтобы объект всячески корчил из себя функцию, разработчики PHP придумали специальный «магический» метод __invoke():

    class Test
    {
        public function __invoke ()
        {
            return 123;
        }
    }
    $func = new Test();
    echo $func(); //123
    


    Подводя итоги: Анонимные функции и замыкания — очень мощный инструмент. И как любой мощный инструмент, требуют очень аккуратного применения. Они могут существенно упростить код программы, сделать его красивее и повысить его читаемость, а могут ровно наоборот — сделать его абсолютно нечитаемым. Замыкания очень часто применяются в качестве функций обратного вызова при программировании графических интерфейсов. Очень удобно вешать их в качестве обработчиков нажатий на разные кнопочки. Но на PHP практически никто не делает программы с GUI (хотя умельцы существуют), и на это есть некоторые причины — PHP все же язык веб-сценариев, а не десктоп приложений. Поэтому анонимные функции хороши в preg_replace_callback, array_filter и тому подобных функциях, а замыкания следует оставить для Javascript, Python и других языков, где они реализованы действительно хорошо и где реально нужны для использования в GUI.

    В заключение: Хочу привести законченный пример использования замыканий с JQuery (при работе с этой библиотекой они используются широко). В примере много вложенных функций, обработчиков, и в них, чтобы избежать постоянных (хоть и быстрых, но некрасивых) поисков DOM-объектов по параметрам, всюду используются переменные уже содержащие нужный объект, доставшиеся от внешней функции (это и есть замыкание). Аналогичный код используется в админке проекта hi-tech.mail.ru, и позволяет динамически добавить возможность редактирования и сохранения через AJAX отдельных блоков страницы (наподобие того, что делает плагин Editable), при этом изначально HTML код страницы не содержит никакой особой разметки для этого.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    <title>dynaedit</title>
    <style type="text/css">
    .msg, .edt {font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 10pt}
    .msg {background-color:#DDf; border: 1px solid #000; padding:2px}
    .edt {margin:-2px 0 -2px -1px; padding:0; width:100%; height:100%; border 0}
    </style>
    <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script>
    $(document).ready(function()
    {
    	$("#admin").click(function()
    	{
    		$(this).remove();
    		$("p.msg").each(function()
    		{
    			var msg_id=this.id.substr(1); //Откуда здесь this? Из each!
    			var msg=$(this); //Объект JQuery из DOM элемента <p>
    			$("<input/>", //Добавим под ним кнопку
    			{
    				type: "button",
    				value: "Править запись #"+msg_id,
    				click: function StartEdit() //При нажатии будем подменять текст внутри p на поле textarea для редактирования
    				{
    					var edt=$("<textarea/>", //Создаем textarea, помещаем вместо текста в p
    					{
    						'class':'edt',
    						value:msg.html().replace(/<br[^>]*>/gim,"\n"), //откуда msg? из родительской функции => замыкание
    						height:msg.height(),
    					}).appendTo(msg.empty());
    					$(this).val("Сохранить запись #"+msg_id).unbind().click(function() //Меняем надпись и обработчик на кнопке
    					{
    						//$.post("/ajax/savemessage",{msg_id:msg_id, msg:edt.val()}, function(data){}); //Отправляем на сервер
    						msg.html(edt.remove().val().replace(/\n/gm,"<br />")); //Убираем textarea, возвращаем текст
    						$(this).val("Править запись #"+msg_id).unbind().click(StartEdit);//Меняем надпись, ставим старый обработчик на кнопке
    						return false;
    					});//Save
    					return false;
    				} //StartEdit()
    			}).insertAfter(this);//<input/>
    		});//$("p.msg").each
    		return false;
    	});//$("#admin").click
    });//$(document).ready
    </script>
    </head>
    
    <body>
    <p id="p1234" class="msg">Это первое сообщение<br />Его можно редактировать!</p>
    <p id="p1235" class="msg">Это второе сообщение<br />Его тоже можно редактировать!<br />P.S. Just 4 lulz</p>
    <p><a href="#" id="admin">Я админ и хочу редактировать!</a></p>
    </body>
    
    </html>
    


    С уважением,
    Отдел исследований и разработки Mail.Ru
    Mail.ru Group
    Building the Internet

    Similar posts

    Comments 69

      +47
      Ого, в mail.ru пресс-секретарь разбирается в замыканиях php.
      Круто.

      замыкания (closures).

      О последних я и хочу рассказать.

      Зачем нужны замыкания в PHP я понимаю слабо.


      Не хватает строчки
      Статью разместила по просьбе JohnDoe, но у него нет кармы чтобы разместить в соответствующем блоге.


      Всех с пятницей.
        +1
        Это к тому, что мог бы запостить автор этой статьи, как делается в блоге компании Abbyy, чтобы он мог отвечать на заданные комментарии/вопросы/размышления
          +1
          Челябинские пресс-секретари настолько суровы, что на завтрак читают MSDN, а в перерывах на рекламу изучают замыкания и пишут статьи.
            +1
            возможно, девелопера _заставили_ написать эту статью. возможно, стимулировали термо-ректально. надо срочно обратиться в комитет по защите прав человека!
            +19
            Я все еще не могу поверить что вижу это:
            а) в блоге Мэйл.ру
            б) от Комисаровой

            Ну да ладно, все равно молодцы, что пишете не только пресс-релизы :-)
              +3
              Валерия, похоже люди чего-то не знают :)
              +5
              Непонятно, зачем делается такой упор на анонимность функций. Какая разница, анонимная функция или нет. Возможность объявлять анонимные функции — это просто синтаксический сахар.

              Замыкания к анонимности функций никакого отношения не имеют. Писать, что замыкание — это комбинация 2 факторов, 1 из которых — анонимная функция — неправильно.
                0
                > Возможность объявлять анонимные функции — это просто синтаксический сахар.
                вообще исторически и логически скорее на оборот, а в php… ну что тут поделаешь :D
                  +2
                  Сахарный синтаксис?
                  +5
                  Снимаю свои претензии к автору топика. Что-то там с терминологией капец какой-то даже в официальном мануале .
                  Anonymous functions, also known as closures

                  Ну и каша. Такое ощущение, как будто они сами не очень понимают, что сделали. Очень странно и удивительно.
                    +1
                    Причём имеют в виду скорее всего просто возможность присваивания функции переменной :)
                    Эта возможность + сохранение родительского scope — это уже хотя бы замыкание.
                      0
                      Че ж тут удивительного? PHP весь – каша. Официальный мануал зачастую вообще содержит документацию багов отдельных версий, так как у языка нет нормальной четкой спецификации.

                      У меня такое ощущение что они сначала что-то кодят а потом кое-как документируют что получилось.
                        0
                        Реализация замыканий в PHP не бесспорна. Порой мне кажется что они специально выбирают самые «хитрые» пути.
                        +2
                        Неверно. Возможность обьявления анонимных функций — удобна для авторов библиотек. Гарантирована непересекаемость по именам.
                        0
                        Ух, что я вижу! Неужели в mail.ru что-то пишут на PHP? Я почему-то полагал, что у вас там все на перле и/или с++.
                          +1
                          Для многих применений PHP эффективнее, чем вышеуказанное.
                          Либо по скорости разработки, либо по производительности, либо по простоте поддержки, либо по цене.
                            0
                            они пали едва ли не последними из крупных российских компаний и таки дали объявление о наборе php разработчиков
                            –2
                            Вообще синтаксически выглядит диковато, в других языках это реализовано лаконичнее.
                            Но что делать, это же PHP.
                              +6
                              Внимание, фокус:

                              www.php.net/manual/en/reserved.classes.php#reserved.classes.closure
                              Closure
                              The predefined final class Closure was introduced in PHP 5.3.0. It is used for internal implementation of anonymous functions.

                              нечеттаель документации детектед.
                                0
                                Вот вот и я подумал, а разве замыкания не нужны для анонимных функции это не одно и тоже?

                                Автор учи мат часть: Closure (computer science)!
                                +2
                                В Си вообще нет замыканий, о боже, как он отстал! Абзац со сравнением lisp'а и php достаточно смешной и нелогичный.

                                Ну а так — да. PHP был типичным императивным языком для быстрых скриптов, и только сейчас вырывается на какой-то уровень технологий.
                                  0
                                  А, и __invoke как раз таки офигенное нововведение, лучше чем просто переменные-функции. Вопросы производительности стоит оставить оптимизаторам. А внутренние процессы в том же JS такие же.
                                    +2
                                    вырывается? по-моему тут он просто пытается догнать.
                                      0
                                      Пытается догнать что? У каждого свое русло, у PHP тоже, и для своего русла он не плох. Разработчики прсто делают нововведения, ускоряют работу языка. Что в этом плохого?
                                    +1
                                    Они тоже люди я проверял :)
                                      +2
                                      лямбда функция это
                                      1) анонимная функция которая может быть сохранена в переменной
                                      2) в отличие от функции созданной create_function уничтожается при выходе из области видимости и не жрет память бесконечно.

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

                                        0
                                        Именно это я и имел в виду говоря «замыкание» (использует переменные родителей) и «анонимная функция» (не использует)! Я понимаю что технически в некоторых языках это одно и то же.
                                        –4
                                        Правильно, зачем делать нормальную реализацию замыканий, ведь для этого придется перелопатить весь говнокод из интерпретатора PHP (слова разработчика, который был в dev team)! Намного лучше сделать идиотский magic method (*объект* используется как функция — WTF?!?!) и добавить синтаксического сахара для создания нужного объекта с таким методом.

                                        Интересно, доступ к родительской области видимости делается при помощи банальных ссылок на нужные переменные, чтобы сборка мусора их не прибила?

                                        А теперь смотрим как это все реализовано в том же Javascript и перестаем удивляется словам про кривую проектировку PHP.
                                          +1
                                          Ну, если очень хочется, в c++ тоже можно объект использовать как функцию. Называется перегрузка оператора ()
                                          –2
                                          >чтобы сборка мусора их не прибила?
                                          1) как может сборка мусора прибить РОДИТЕЛЬСКИЕ переменные?
                                          2) какая сборка мусора в PHP? там тупо счетчик ссылок.
                                            +1
                                            Открываем википедию и узнаем, что сборка мусора в простейшем случае делается именно при помощи подсчета ссылок. Для сборки мусора не важно какая область видимости. Вообще.
                                            +4
                                            Один только phpdaemon практически весь построен на замыканиях, так как это практически единственая метода для реализации асинхронности без гемороя.
                                              +7
                                              В корпоративном блоге. Неожиданно.
                                                +9
                                                Автор статьи, я. Готов отдуваться.

                                                P.S. В продакшене у нас (на hitech.mail.ru) PHP действительно не используется. Зато используется JQuery. Просто PHP интересен в плане синтаксиса и реализации замыканий, да и вообще релиз 5.3 очень интересный.
                                                  0
                                                  Вообще как я писал выше замыкания нужны для создания анонимных функции, странно что вы этого не знаете. Вся статья не о замыканиях, а о анонимных функциях!
                                                    +1
                                                    Мы говорим об одном и том же, разница в терминологии.
                                                    +2
                                                    Я удивлен, что статья попала на главную…

                                                    Причин две:
                                                    1) Статья совершенно не про «Замыкания в PHP»… Об этом хотябы говорит ваша фраза «Зачем нужны замыкания в PHP я понимаю слабо».
                                                    2) По поводу замыканий JS — полно статей на Хабре. Я негодую — что нового в этой статье?

                                                    Аннонимные функции у меня во FW используются так:
                                                    getElementObject('Form')
                                                      ->onValidate(function($fields){
                                                       //проверки
                                                      })
                                                      ->onSubmit(function($fields){
                                                       //что делаем, если порядок
                                                      })
                                                      ->onError(function($fields){
                                                       //что делаем, если всё плохо
                                                      });


                                                    * This source code was highlighted with Source Code Highlighter.


                                                    Замыкания так:
                                                    $login = Auth::getLogin();

                                                    getElementObject('Form')
                                                      ->onValidate(function($fields) use ($login){
                                                        $newLogin = $fields->getElementObject('.name')->getValue();
                                                        //Проверяем, что пользователь ввел не сам себя
                                                        return $login != $newLogin;
                                                      });


                                                    * This source code was highlighted with Source Code Highlighter.

                                                    Смысл этого в том, чтобы определять $login не внутри Validate функции.
                                                      +1
                                                      Код во втором примере можно назвать практичным, но трудно назвать элегантным. Синтаксис PHP для замыканий тоже не добавляет изящества.
                                                        +1
                                                        В вашем случае, элегантность кода = создание дополнительного Validate класса в который идет загрузка $login, затем установка полю проверки?

                                                        class LoginValidate extends Validate{
                                                          function setLogin($login){
                                                           $this->login = $login;
                                                          }

                                                          function onValidate($value){
                                                            return $this->login != $value;
                                                          }
                                                        }

                                                        ///...

                                                        $login = Auth::getLogin();

                                                        getElementObject('Field.name')
                                                          ->onValidate(
                                                             classBuilder::createClass('LoginValidate')
                                                               ->setLogin($login)
                                                          );

                                                        * This source code was highlighted with Source Code Highlighter.


                                                        Объясните, как по вашему поступить элегантно?
                                                          +1
                                                          Да примерно так бы я и сделал. Вот даже в простом примере вы унаследовали свой класс от некого базового класса. Собственно возможность повторного использования кода, упрощение отладки мне и видится в преимуществах этого варианта.
                                                            0
                                                            Я признаю, что моя реализация проверки (в первом примере) туповата. Это случилось потому что это был пример, а не реальный код.

                                                            Но вариант с классами — это засирание кодом и усложнение структуры. Очевидно, что людям разобраться и найти нужное будет намного сложнее. Создавать новый класс для каждой проверки? Создать один класс, который будет делать все проверки, который нужно искать по названию?

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

                                                            Второй пример необходим только в случае частого использования.
                                                      0
                                                      p.s. А, ну и почитайте, как их можно использовать… Первая ссылка google… fabien.potencier.org/article/17/on-php-5-3-lambda-functions-and-closures
                                                      +3
                                                      1. Зачем вы обрушили на нас этот баян? Я об писал больше года назад (18 мая 2009 года).
                                                      2. То что вы слабо представляете зачем нужны closures в PHP это говорит лишь о том что вы не в теме таких вещей как phpDaemon :-) Да и многих других интересных вещей.
                                                        +2
                                                        Лучше вместо понтов и рассказали, зачем же всё-таки замыкания нужны и что за вещи такие phpDaemon. А то как детсаде ей богу «нет, я первый в песочницу залез, нет, это моё ведерко!»
                                                      +3
                                                      P.S. Замыкания в PHP нужны потому что нам надоело видеть create_function под ободками наших унитазов.
                                                        –3
                                                        Мне кажется, замыкания вообще не очень красиво смотрятся в ООП. Но это на мой вкус.
                                                          +1
                                                          Вам и goto подозрительным кажется!
                                                            –1
                                                            Почему вы говорите так, как будто в этом есть что-то плохое?
                                                              +2
                                                              а что вы имеете против goto, мне лично кажется странно что его ввели так поздно!
                                                        0
                                                        1. основное отличие от create_function или eval в возможности нормальной отладки.

                                                        2. в руби (который также ориентирован на веб-скрипты) активно используются замыкания.
                                                          +1
                                                          на python надо переходить
                                                            +3
                                                            По-моему это копипаст старой статьи. Гуглил замыкания и случайно напоролся в архиве за 2009г:

                                                            abramov.tv/2009/10/chto-takoe-zamyikaniya-v-php-i-javascript/
                                                              +3
                                                              Тогда простите меня, это ппц — за год не разобраться, для чего они нужны…
                                                                0
                                                                За год я убедился, что лично мне в PHP они не нужны. Очевидно же, что мое суждение субъективно. Ваше, кстати, тоже. Мы же с вами выше убедились, что все то же самое можно сделать и без замыканий. При этом я не отказываю вашему коду в практичности. И считаю здорово, что вы нашли им применение. Только не понимаю почему вы так их отстаиваете?
                                                                  +1
                                                                  Тимур, огромное спасибо, вы первый кто мне смог полноценно и доходчиво объяснить, что такое замыкания и лямбда функции (почему они так называются) и для чего нужны :)
                                                                    0
                                                                    И для чего в PHP нужны замыкания? :)
                                                                      0
                                                                      Какая разница в PHP или не в PHP, просто теперь понятно, что это такое :)

                                                                      0
                                                                      Спасибо! Я старался написать просто и с примерами. За это в основном и получил упреки в том, что в статье нет ничего сверхъестественного. Приятно, что вам она оказалась не бесполезной!
                                                                  0
                                                                  А я-то обрадовался…
                                                                    –2
                                                                    Причем копипаст практически дословный, включая примеры и речевые обороты!
                                                                    0
                                                                    Автору:

                                                                    Все эти прелести действительно очень полезны. Например, используем шаблоны на чистом PHP, layout.php:

                                                                    <div id=«header»><%= yield_content('header') %>

                                                                    и где-нибудь

                                                                    <% for_region('header', function() { %>
                                                                    тра-та-та
                                                                    <% }); %>

                                                                    Понятно, идея взята из Rails.
                                                                      +3
                                                                      Вернемся к PHP. В нем все не так красиво как в Javascript. Во-первых, для того чтобы функция могла использовать переменные родительской функции, надо это явно указать в ее определении (это следует из идеологии языка)

                                                                      Мне это наоборот представляется крайне разумным ходом, поскольку в таком случае все ненужные для замыкания локальные переменные будут удалены после завершения вызова функции, освободив память.
                                                                        0
                                                                        Не будут, память освобождается не сразу.
                                                                          0
                                                                          Согласен, не совсем корректно выразился. Но поскольку в PHP с некоторых пор есть сборщик мусора, то в какой-то момент она таки освободится — за исключением переменных, использованных в замыкании, что весьма логично на мой взгляд. Это я и хотел сказать.
                                                                        0
                                                                        Пример, где замыкания реально нужны:
                                                                        www.pgregg.com/projects/php/preg_find/preg_find.phps
                                                                        искать строку: $filesort =
                                                                        Автор конечно гм… со своеобразным кодстайлом, но файлик понятный без доп знаний.
                                                                          –2
                                                                          Мне есть что вам ответить. Похоже это библиотека и стиль там процедурный. Соответственно create_function используется прежде всего, чтобы не засирать глобальное пространство имен (но, кстати, все равно это делает).

                                                                          А если бы они применили ООП подход?

                                                                          Во первых они бы избавились от некрасивых
                                                                          define('PREG_FIND_RECURSIVE', 1);
                                                                          define('PREG_FIND_DIRMATCH', 2);

                                                                          засунув все константы в класс.

                                                                          Во вторых они бы сделали сортировку, передав в uasort метод класса и из метода имея доступ ко всем свойствам, в том числе параметрам сортировки.

                                                                          Разве это не сделало бы код прозрачнее и юзабельнее?
                                                                          0
                                                                          позитивно
                                                                            0
                                                                            Осталось дождаться пока array_map() и подобные функцию научатся работать в несколько потоков.

                                                                            Only users with full accounts can post comments. Log in, please.