Закрытие или создание_функции в PHP

Я принял решение использовать блокировки для своих обратных вызовов вместо create_function и как таковые поддерживать PHP > 5.3 в основном из-за повышенной отладки, а также потому, что я предположил (что это такое, что говорят о допущении?), что накладные расходы "на лету" компиляции create_function в моей ситуации, вероятно, компенсировали бы любые дополнительные сравнения и такие, которые должны были быть сделаны внутри функции.

Это может быть и так (для моего приложения), и требуется дополнительное тестирование, но меня заинтересовал вывод этого (очень) простого теста, который показывает, что метод create_function более чем в два раза быстрее, чем закрытие, когда он может удалить только четыре условных выражения (и concats). Очевидно, что в моем тестовом случае нет дополнительной обработки, и именно там большая часть скорости будет получена или потеряна, но в случае, когда у вас мало дополнительной обработки, но есть много условных выражений (которые можно удалить) и callback называется достаточно раза, я начал думать, что лучше использовать create_function.

Однако с очевидным сходством между create_function и eval я опасаюсь этого.

Итак, главный вопрос в том, каковы различия между анонимными функциями, созданными с помощью create_function, и с закрытием?

Несколько конкретных вопросов, о которых я думаю, будут create_function работать даже если функция eval отключена? И я уверен, что где-то недавно я где-то читал, что функции create_function будут загрязнять глобальное (или класс) пространство имен, даже если объявлены как внутренние функции, но закрытие не будет. Я не могу найти ссылку на это сейчас, но являются ли они или оба из этих утверждений истинными?


Это небольшое испытание, которое я выполнил:

<?php

function foo($a=true, $b=true, $c=true, $d=true)
{
    $inner1 = create_function(
        '', 
        '$r = \''.($a ? 'a' : '').
                  ($b ? 'b' : '').
                  ($c ? 'c' : '').
                  ($d ? 'd' : '').'\';
         return $r;'
    );  


    $inner2 = function() use ($a, $b, $c, $d) 
    {   
        $r = ''; 
        if($a) { $r .= 'a'; }
        if($b) { $r .= 'b'; }
        if($c) { $r .= 'c'; }
        if($d) { $r .= 'd'; };
        return $r; 
    };  


    $time = microtime(true);
    for ($x=0; $x<99999; ++$x)
    {   
        $i1out = $inner1();
    }   
    echo '1:'.(microtime(true)-$time).'<br>';

    $time = microtime(true);
    for ($x=0; $x<99999; ++$x)
    {   
        $i2out = $inner2();
    }   
    echo '2:'.(microtime(true)-$time).'<br>';

    echo var_dump($i1out===$i2out).'<br>';
}

foo();

Ответ 1

Конструкция function() {..} является анонимной функцией, и эта функция часто реализуется вместе с закрытиями. Ни create_function, ни анонимные функции не загрязняют глобальное пространство имен.

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

Однако крайне маловероятно, что разница между анонимными функциями и create_function является источником проблем с производительностью. Поэтому я бы выбрал более читаемую форму анонимной функции, если вам так повезло иметь целевую платформу с php > 5.3.

Ответ 2

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

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

for ($i = 0; $i < 1000000; $i++) {
  $f = create_function('', '');
  // do stuff

  // don't use $f anywhere after this point
}

тогда как с анонимными функциями этого не произойдет (закрытие будет собираться мусором).