CakeFest 2024: The Official CakePHP Conference

create_function

(PHP 4 >= 4.0.1, PHP 5, PHP 7)

create_functionСоздаёт функцию динамически, оценивая строку кода

Внимание

Эта функция объявлена УСТАРЕВШЕЙ начиная с PHP 7.2.0 и была УДАЛЕНА в версии PHP 8.0.0. Использовать эту функцию крайне не рекомендуется.

Описание

create_function(string $args, string $code): string

Создаёт функцию динамически из переданных параметров и возвращает её уникальное имя.

Предостережение

Функция внутри себя делает вызов функции eval(), а значит имеет такие же проблемы с безопасностью, как и eval(). Также у неё плохие характеристики производительности и использования памяти, поскольку созданные функции являются глобальными и не могут быть освобождены.

Используйте анонимные функции.

Список параметров

Обычно рекомендуется передавать параметры в виде строк с одинарной кавычкой. При использовании строк с двойной кавычкой имена переменных в коде должны быть тщательно экранированы, например, вот так: \$somevar.

args

Аргументы функции в виде строки, разделённой запятыми.

code

Код функции.

Возвращаемые значения

Возвращает уникальное имя функции в виде строки или false, если возникла ошибка. Обратите внимание, что имя содержит непечатаемый символ ("\0"), поэтому следует соблюдать осторожность при печати имени или включении его в любую другую строку.

Примеры

Пример #1 Создание функции динамически с помощью create_function() или анонимных функций

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

<?php
$newfunc
= create_function('$a,$b', 'return "ln($a) + ln($b) = " . log($a * $b);');
echo
$newfunc(2, M_E) . "\n";
?>

Теперь тот же код, используя анонимную функцию; обратите внимание, что код и аргументы больше не содержатся в строках:

<?php
$newfunc
= function($a,$b) { return "ln($a) + ln($b) = " . log($a * $b); };
echo
$newfunc(2, M_E) . "\n";
?>

Результат выполнения приведённого примера:

ln(2) + ln(2.718281828459) = 1.6931471805599

Пример #2 Создание общей функции-обработчика с помощью create_function() или анонимных функций

Другим вариантом использования может быть общая функция-обработчик, которая может применять набор операций к списку параметров:

<?php
function process($var1, $var2, $farr)
{
foreach (
$farr as $f) {
echo
$f($var1, $var2) . "\n";
}
}

// создаём кучу математических функций
$farr = array(
create_function('$x,$y', 'return "тригонометрия: ".(sin($x) + $x*cos($y));'),
create_function('$x,$y', 'return "гипотенуза: ".sqrt($x*$x + $y*$y);'),
create_function('$a,$b', 'if ($a >=0) {return "b*a^2 = ".$b*sqrt($a);} else {return false;}'),
create_function('$a,$b', "return \"min(b^2+a, a^2,b) = \".min(\$a*\$a+\$b,\$b*\$b+\$a);"),
create_function('$a,$b', 'if ($a > 0 && $b != 0) {return "ln(a)/b = ".log($a)/$b; } else { return false; }')
);

echo
"\nИспользование первого массива динамических функций\n";
echo
"Параметры: 2.3445, M_PI\n";
process(2.3445, M_PI, $farr);

// теперь создаём кучу функций обработки строк
$garr = array(
create_function('$b,$a', 'if (strncmp($a, $b, 3) == 0) return "** \"$a\" '.
'и \"$b\"\n** для меня одинаковы! (смотря по первым 3 символам)";'),
create_function('$a,$b', 'return "CRCs: " . crc32($a) . ", ".crc32($b);'),
create_function('$a,$b', 'return "similar(a,b) = " . similar_text($a, $b, $p) . "($p%)";')
);
echo
"\nИспользование второго массива динамических функций\n";
process("Варкалось. Хливкие шорьки пырялись по наве", "Варан ползёт", $garr);
?>

И снова, тот же самый код с использованием анонимных функций. Обратите внимание, что имена переменных в коде больше не нужно экранировать, поскольку они не заключены в строку.

<?php
function process($var1, $var2, $farr)
{
foreach (
$farr as $f) {
echo
$f($var1, $var2) . "\n";
}
}

// создаём кучу математических функций
$farr = array(
function(
$x,$y) { return "тригонометрия: ".(sin($x) + $x*cos($y)); },
function(
$x,$y) { return "гипотенуза: ".sqrt($x*$x + $y*$y); },
function(
$a,$b) { if ($a >=0) {return "b*a^2 = ".$b*sqrt($a);} else {return false;} },
function(
$a,$b) { return "min(b^2+a, a^2,b) = " . min($a*$a+$b, $b*$b+$a); },
function(
$a,$b) { if ($a > 0 && $b != 0) {return "ln(a)/b = ".log($a)/$b; } else { return false; } }
);

echo
"\nИспользование первого массива динамических функций\n";
echo
"Параметры: 2.3445, M_PI\n";
process(2.3445, M_PI, $farr);

// теперь создаём кучу функций обработки строк
$garr = array(
function(
$b,$a) { if (strncmp($a, $b, 3) == 0) return "** \"$a\" " .
"и \"$b\"\n** для меня одинаковы! (смотря по первым 3 символам)"; },
function(
$a,$b) { return "CRCs: " . crc32($a) . ", ".crc32($b); },
function(
$a,$b) { return "similar(a,b) = " . similar_text($a, $b, $p) . "($p%)"; }
);
echo
"\nИспользование второго массива динамических функций\n";
process("Варкалось. Хливкие шорьки пырялись по наве", "Варан ползёт", $garr);
?>

Результат выполнения приведённого примера:

Использование первого массива динамических функций
Параметры: 2.3445, M_PI
тригонометрия: -1.6291725057799
гипотенуза: 3.9199852871011
b*a^2 = 4.8103313314525
min(b^2+a, a^2,b) = 8.6382729035898
ln(a)/b = 0.27122299212594

Использование второго массива динамических функций
** "Варан ползёт" и "Варкалось. Хливкие шорьки пырялись по наве"
** для меня одинаковы! (смотря по первым 3 символам)
CRCs: 2672527412, 2269828269
similar(a,b) = 16(31.683168316832%)

Пример #3 Использование динамических функций в качестве callback-функций

Возможно, самым распространённым использованием динамических функций является передача их в качестве callback-функций, например, при использовании array_walk() или usort().

<?php
$av
= array("the ", "a ", "that ", "this ");
array_walk($av, create_function('&$v,$k', '$v = $v . "mango";'));
print_r($av);
?>

Преобразование приведённого выше кода в анонимную функцию:

<?php
$av
= array("о, ", "эх, ", "то ", "это ");
array_walk($av, create_function('&$v,$k', '$v = $v . "манго";'));
print_r($av);
?>

Результат выполнения приведённого примера:

Array
(
  [0] => о, манго
  [1] => эх, манго
  [2] => то манго
  [3] => это манго
)

Сортировка строк от самой длинной до самой короткой с помощью create_function():

<?php
$sv
= array("мало", "много", "большая строка", "строка строка строка");
echo
"Оригинальный массив:\n";
print_r($sv);
echo
"Отсортированный:\n";
usort($sv, create_function('$a,$b','return strlen($b) - strlen($a);'));
print_r($sv);
?>

Преобразование приведённого выше кода в анонимную функцию:

<?php
$sv
= array("мало", "много", "большая строка", "строка строка строка");
echo
"Оригинальный массив:\n";
print_r($sv);
echo
"Отсортированный:\n";
usort($sv, function($a,$b) { return strlen($b) - strlen($a); });
print_r($sv);
?>

Результат выполнения приведённого примера:

Оригинальный массив:
Array
(
    [0] => мало
    [1] => много
    [2] => большая строка
    [3] => строка строка строка
)
Отсортированный:
Array
(
    [0] => строка строка строка
    [1] => большая строка
    [2] => много
    [3] => мало
)

Смотрите также

add a note

User Contributed Notes 22 notes

up
18
tamagochi_man
5 years ago
Whilst it was correct 11 years ago, the statement of Dan D is not so correct any moreю Anonymous functions are now objects of a class Closure and are safely collected by garbage collector.
up
4
Josh J
17 years ago
In regards to the recursion issue by info at adaniels dot nl

Anon function recursion by referencing the function variable in the correct scope.
<?php
$fn2
= create_function('$a', 'echo $a; if ($a < 10) call_user_func($GLOBALS["fn2"], ++$a);');
$fn2(1);
?>
up
12
Dan D
17 years ago
Beware when using anonymous functions in PHP as you would in languages like Python, Ruby, Lisp or Javascript. As was stated previously, the allocated memory is never released; they are not objects in PHP -- they are just dynamically named global functions -- so they don't have scope and are not subject to garbage collection.

So, if you're developing anything remotely reusable (OO or otherwise), I would avoid them like the plague. They're slow, inefficient and there's no telling if your implementation will end up in a large loop. Mine ended up in an iteration over ~1 million records and quickly exhasted my 500MB-per-process limit.
up
3
kak dot serpom dot po dot yaitsam at gmail dot com
11 years ago
Try this to boost performance of your scripts (increase maxCacheSize):

<?php
runkit_function_copy
('create_function', 'create_function_native');
runkit_function_redefine('create_function', '$arg,$body', 'return __create_function($arg,$body);');

function
__create_function($arg, $body) {
static
$cache = array();
static
$maxCacheSize = 64;
static
$sorter;

if (
$sorter === NULL) {
$sorter = function($a, $b) {
if (
$a->hits == $b->hits) {
return
0;
}

return (
$a->hits < $b->hits) ? 1 : -1;
};
}

$crc = crc32($arg . "\\x00" . $body);

if (isset(
$cache[$crc])) {
++
$cache[$crc][1];
return
$cache[$crc][0];
}

if (
sizeof($cache) >= $maxCacheSize) {
uasort($cache, $sorter);
array_pop($cache);
}

$cache[$crc] = array($cb = eval('return function('.$arg.'){'.$body.'};'), 0);
return
$cb;
}
?>
up
2
info at adaniels dot nl
17 years ago
Note that using __FUNCTION__ in a an anonymous function, will always result '__lambda_func'.

<?php
$fn
= create_function('', 'echo __FUNCTION__;');
$fn();
// Result: __lambda_func
echo $fn;
// Result: ºlambda_2 (the actual first character cannot be displayed)
?>

This means that a anonymous function can't be used recursively. The following code (recursively counting to 10) results in an error:
<?php
$fn2
= create_function('$a', 'echo $a; if ($a < 10) call_user_func(__FUNCTION__, $a++);');
$fn2(1);
// Warning: call_user_func(__lambda_func) [function.call-user-func]: First argument is expected to be a valid callback in T:/test/test.php(21) : runtime-created function on line 1
?>
up
1
kkaiser at revolution-records dot net
16 years ago
In the process of migrating a PHP4 codebase to PHP5, I ran into a peculiar problem. In the library, every class was derived from a generic class called 'class_container'. 'class_container' contained an array called runtime_functions and a method called class_function that was as follows:

<?php
function class_function($name,$params,$code) {

$this->runtime_functions[$name] = create_function($params,$code);

}
?>

In a subclass of class_container, there was a function that utilized class_function() to store some custom lambda functions that were self-referential:

<?php
function myfunc($name,$code) {

$this->class_function($name,'$theobj','$this=&$theobj;'.$code);

}
?>

In PHP4, this worked just fine. The idea was to write blocks of code at the subclass level, such as "echo $this->id;", then simply $MYOBJ->myfunc("go","echo $this->id;"); and later call it like $MYOBJ->runtime_functions["go"]();

It essentially worked exactly like binding anonymous functions to objects in Javascript.

Note how the "$this" keyword had to be manually redefined for the $code block to work.

In PHP5, however, you can't redeclare $this without getting a fatal error, so the code had to be updated to:

<?php
function myfunc($name,$code) {

$this->class_function($name,'$this',$code);

}
?>

Apparently create_function() allows you to set $this via a function argument, allowing you to bind anonymous functions to instantiated objects. Thought it might be useful to somebody.
up
1
Dave H
13 years ago
The following function is very useful for creating an alias of a user function.
For built-in functions, it is less useful because default values are not available, so function aliases for built-in functions must have all parameters supplied, whether optional or not.

<?php
function create_function_alias($function_name, $alias_name)
{
if(
function_exists($alias_name))
return
false;
$rf = new ReflectionFunction($function_name);
$fproto = $alias_name.'(';
$fcall = $function_name.'(';
$need_comma = false;

foreach(
$rf->getParameters() as $param)
{
if(
$need_comma)
{
$fproto .= ',';
$fcall .= ',';
}

$fproto .= '$'.$param->getName();
$fcall .= '$'.$param->getName();

if(
$param->isOptional() && $param->isDefaultValueAvailable())
{
$val = $param->getDefaultValue();
if(
is_string($val))
$val = "'$val'";
$fproto .= ' = '.$val;
}
$need_comma = true;
}
$fproto .= ')';
$fcall .= ')';

$f = "function $fproto".PHP_EOL;
$f .= '{return '.$fcall.';}';

eval(
$f);
return
true;
}
?>
up
1
lombax85 at gmail dot com
2 years ago
For who *really* needs the create_function() on php8 (because of legacy code that cannot be changed easily) there is this: "composer require lombax85/create_function".
up
0
CertaiN
10 years ago
Best wapper:

<?php

function create_lambda($args, $code) {
static
$func;
if (!isset(
$func[$args][$code])) {
$func[$args][$code] = create_function($args, $code);
}
return
$func[$args][$code];
}
up
0
neo at nowhere dot com
15 years ago
In response to kkaiser at revolution-records dot net's note, even tho PHP will allow you to use
<?
$myfunc = create_function('$this', $code);
?>
You can NOT use a reference to "$this" inside of the anonymous function, as PHP will complain that you are using a reference to "$this" in a non-object context.

Currently, I have not found a work-around for this...
up
0
Alan FUNG
15 years ago
$f = create_function('','echo "function defined by create_function";');
$f();

result:
function defined by create_function

You may define no return in function body while you are using create_function.
up
0
Rene Saarsoo
16 years ago
Here has been some discussion about the "memory leak" create_function() can create.

What create_function() actually does, is creating an ordinary function with name chr(0).lambda_n where n is some number:

<?php
$f
= create_function('', 'return 1;');

function
lambda_1() { return 2; }

$g = "lambda_1";
echo
$g(); // outputs: 2

$h = chr(0)."lambda_1";
echo
$h(); // outputs: 1
?>
up
0
TSE-WebDesign
16 years ago
Here's how to call a runtime-created function from another runtime-created function:
<?php
$get_func
= create_function('$func', 'return substr($func,1);');
$get_value = create_function('$index','return pow($index,$index);');
$another_func = create_function('$a', '$func="\x00"."'.$get_func($get_value).'";return $func($a);');
echo
$another_func(2); # result is 4
?>
up
0
Phlyst
17 years ago
In reply to info at adaniels dot nl:

You may not be able to use __FUNCTION__ in a lambda (thanks for pointing it out; I was having that problem just now), but you can use $GLOBALS to work around it if you're assigning the function to a variable. I reimplemented array_walk_recursive() in PHP4 like this:

<?php
$array_walk_recursive
= create_function('&$array, $callback',
'foreach($array as $element) {
if(is_array($element)) {
$funky = $GLOBALS["array_walk_recursive"];
$funky($element, $callback);
}
else {
$callback($element);
}
}'
);
?>
up
0
josh at janrain dot com
18 years ago
Beware! This is merely a convenience function that generates a unique name for a regular function. It is *not* a closure or even an anonymous function. It is just a regular function that gets named for you.
up
0
Joshua E Cook
18 years ago
Functions created by create_function() cannot return a value by reference. The function below creates a function that can. The arguments are the same as create_function(). Note that these arguments are passed, unmodified, to eval(), so be sure that data passed in is sanitized.

<?php
/**
* create_ref_function
* Create an anonymous (lambda-style) function
* which returns a reference
* see http://php.net/create_function
*/
function
create_ref_function( $args, $code )
{
static
$n = 0;

$functionName = sprintf('ref_lambda_%d',++$n);

$declaration = sprintf('function &%s(%s) {%s}',$functionName,$args,$body);

eval(
$declaration);

return
$functionName;
}
?>
up
0
boards at gmail dot com
18 years ago
If you were checking to see if a function is made properly, this would be a better way of checking:

<?php
$fnc
= @create_function('$arg1,$arg2,$arg3', 'return true;');
# make that function whatever you want
if (empty($fnc)) {
die(
'Could not create function $fnc.');
}

# although, the follow will NOT work
if (empty(create_function('$arg', 'return $arg;'))) {
die(
'Could not create anonymous function.');
}
# you would get an error regarding not being able to use a
# return value in writeable context (i.e. a return value is
# a const in C, and the function empty() doesn't use a
# const void* parameter
?>
up
0
MagicalTux at FF.ST
20 years ago
neo at gothic-chat d0t de wrote :
Beware of memory-leaks, the garbage-collection seems to 'oversee' dynamically created functions!

Not really...

In fact, PHP can not "unassign" functions. So if you create a function, it won't be deleted until the end of the script, even if you unset the variable containing its name.

If you need to change a part of a function everytime you run a loop, think of a way to make a more general function or try using eval :) (functions are made to be re-used. If you need to run your own piece of code once, eval is much better).
up
0
DB on music_ml at yahoo dot com dot ar
20 years ago
[EDIT by danbrown AT php DOT net: Combined user-corrected post with previous (incorrect) post.]

You can't refer to a class variable from an anonymous function inside a class method using $this. Anonymous functions don't inherit the method scope. You'll have to do this:

<?php
class AnyClass {

var
$classVar = 'some regular expression pattern';

function
classMethod() {

$_anonymFunc = create_function( '$arg1, $arg2', 'if ( eregi($arg2, $arg1) ) { return true; } else { return false; } ' );

$willWork = $_anonymFunc('some string', $classVar);

}

}
?>
up
0
x-empt[a_t]ispep.cx
22 years ago
Create_function enables the ability to change the scope of functions. You might have a class where it needs to define a GLOBAL function. This is possible, like:

<?php
class blah {
function
blah() {
$z=create_function('$arg1string','return "function-z-".$arg1string;');
$GLOBALS['z']=$z;
}
}
$blah_object=new blah;

$result=$GLOBALS['z']('Argument 1 String');
echo
$result;
?>

Making a function escape it's defined scope can be useful in many situations.
up
-1
edgar at goodforall dot eu
14 years ago
Just a little toy I thought up, I would like to share. Creates an anonymous function, which let you use a class as a function.

In php 5.3 there is support for real functors (trough __invoke):

<?php
function createFunctor($className){
$content = "
static \$class;
if(!\$class){
\$class = new
$className;
}
return \$class->run(\$args);
"
;
$f = create_function('$args', $content);
return
$f;

}
class
test {
public function
run($args){
print
$args;
}
}
$test = createFunctor('test');
$test('hello world');
?>
up
-1
neo at gothic-chat d0t de
20 years ago
Beware of memory-leaks, the garbage-collection seems to 'oversee' dynamically created functions!

I used a function like this to replace special characters in links with their htmlentities:
<?php
$text
= preg_replace_callback (
"/(<(frame src|a href|form action)=\")([^\"]+)(\"[^>]*>)/i",
create_function (
'$matches',
'return $matches[1] . htmlentities ($matches[3]) . $matches[4];'
),
$text);
?>

After 1000 calls, the process used about 5MB more than before. In my situation this boosted up the memory-size of one PHP-process up to over 100MB!

In such cases, better store the function in a global variable.
To Top