CakeFest 2024: The Official CakePHP Conference

create_function

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

create_functionErzeugt eine Funktion dynamisch durch Auswertung einer Zeichenkette mit Code

Warnung

Diese Funktion ist seit PHP 7.2.0 als DEPRECATED (veraltet) markiert und wurde in PHP 8.0.0 ENTFERNT. Von der Verwendung dieser Funktion wird dringend abgeraten.

Beschreibung

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

Erzeugt aus den übergebenen Parametern dynamisch eine Funktion und gibt einen eindeutigen Namen für sie zurück.

Achtung

Diese Funktion führt intern eval() aus und hat daher die gleichen Sicherheitsprobleme wie eval(). Außerdem zeigt diese Funktion ein schlechtes Verhalten in Bezug auf Leistung und Speicherverbrauch, da die erzeugten Funktionen global sind und nicht mehr freigegeben werden können.

Stattdessen sollten die nativ vorhandenen anonymen Funktionen verwendet werden.

Parameter-Liste

Normalerweise ist es ratsam, diese Parameter als Zeichenketten in einfachen Anführungszeichen zu übergeben. Wenn sie in doppelten Anführungszeichen übergeben werden, müssen die Variablennamen im Code sorgfältig maskiert werden, z. B. \$somevar.

args

Die Funktionsargumente in Form einer einzelnen durch Komma getrennten Zeichenkette.

code

Der Code der Funktion.

Rückgabewerte

Gibt einen eindeutigen Funktionsnamen als Zeichenkette zurück. Bei einem Fehler wird false zurückgegeben. Es ist zu beachten, dass der Name ein nicht druckbares Zeichen enthält ("\0"), weshalb Vorsicht geboten ist, wenn der Name gedruckt oder in eine andere Zeichenkette eingefügt werden soll.

Beispiele

Beispiel #1 Dynamisches Erzeugen einer Funktion, mit create_function() oder anonymen Funktionen

Eine dynamisch erstellte Funktion kann verwendet werden, um (zum Beispiel) eine Funktion aus Informationen zu erstellen, die zur Laufzeit gesammelt wurden. Zuerst unter Verwendung von create_function():

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

Und nun der gleiche Code unter Verwendung einer anonymen Funktion. Zu beachten ist, dass der Code und die Parameter nicht mehr in Zeichenketten eingebettet sind:

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

ln(2) + ln(2.718281828459) = 1.6931471805599

Beispiel #2 Erstellen einer allgemeinen Verarbeitungsfunktion mit create_function() oder anonymen Funktionen

Eine andere Verwendungsmöglichkeit wäre, eine allgemeine Verarbeitungsfunktion zu erstellen, die eine Reihe von Operationen auf eine Liste von Parametern anwenden kann:

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

// Nun erzeugen wir eine Reihe mathematischer Funktionen
$farr = array(
create_function('$x,$y', 'return "etwas Trigonometrie: ".(sin($x) + $x*cos($y));'),
create_function('$x,$y', 'return "eine Hypotenuse: ".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
"\nWir benutzen nun das erste Array von dynamischen Funktionen\n";
echo
"Parameter: 2.3445, M_PI\n";
process(2.3445, M_PI, $farr);

// Nun erzeugen wir eine Reihe von Funktionen zur Bearbeitung von Zeichenketten
$garr = array(
create_function('$b,$a', 'if (strncmp($a, $b, 3) == 0) return "** \"$a\" '.
'und \"$b\"\n** sehen für mich gleich aus! (unter Betrachtung der ersten 3 Zeichen)";'),
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
"\nWir benutzen nun das zweite Array von dynamischen Funktionen\n";
process("Twas brilling and the slithy toves", "Twas the night", $garr);
?>

Hier ist noch einmal derselbe Code unter Verwendung einer anonymen Funktion. Es ist zu beachten, dass die Variablennamen in diesem Code nicht mehr maskiert werden müssen, da sie sich nicht in einer Zeichenkette befinden.

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

// Nun erzeugen wir eine Reihe mathematischer Funktionen
$farr = array(
function(
$x,$y) { return "etwas Trigonometrie: ".(sin($x) + $x*cos($y)); },
function(
$x,$y) { return "eine Hypotenuse: ".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
"\nWir benutzen nun das erste Array von dynamischen Funktionen\n";
echo
"Parameter: 2.3445, M_PI\n";
process(2.3445, M_PI, $farr);

// Nun erzeugen wir eine Reihe von Funktionen zur Bearbeitung von Zeichenketten
$garr = array(
function(
$b,$a) { if (strncmp($a, $b, 3) == 0) return "** \"$a\" " .
"und \"$b\"\n** sehen für mich gleich aus! (unter Betrachtung der ersten 3 Zeichen"; },
function(
$a,$b) { return "CRCs: " . crc32($a) . ", ".crc32($b); },
function(
$a,$b) { return "similar(a,b) = " . similar_text($a, $b, $p) . "($p%)"; }
);
echo
"\nWir benutzen nun das zweite Array von dynamischen Funktionen\n";
process("Twas brilling and the slithy toves", "Twas the night", $garr);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

Wir benutzen nun das erste Array von dynamischen Funktionen
Parameter: 2.3445, M_PI
etwas Trigonometrie: -1.6291725057799
eine Hypotenuse: 3.9199852871011
b*a^2 = 4.8103313314525
min(b^2+a, a^2,b) = 8.6382729035898
ln(a)/b = 0.27122299212594

Wir benutzen nun das zweite Array von dynamischen Funktionen
** "Twas the night" und "Twas brilling and the slithy toves"
** sehen für mich gleich aus! (unter Betrachtung der ersten 3 Zeichen)
CRCs: 3569586014, 342550513
similar(a,b) = 11(45.833333333333%)

Beispiel #3 Gebrauch der anonymen Funktionen als Callback-Funktion

Wahrscheinlich liegt der häufigste Anwendungsfall für dynamische Funktionen darin, sie als Callbacks zu übergeben, also z. B. beim Gebrauch von array_walk() oder usort().

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

Umgewandelt in eine anonyme Funktion:

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

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

Array
(
  [0] => the mango
  [1] => a mango
  [2] => that mango
  [3] => this mango
)

Sortieren von Zeichenketten von der längsten zur kürzesten mit create_function():

<?php
$sv
= array("small", "a big string", "larger", "it is a string thing");
echo
"Original:\n";
print_r($sv);
echo
"Sortiert:\n";
usort($sv, create_function('$a,$b','return strlen($b) - strlen($a);'));
print_r($sv);
?>

Umgewandelt in eine anonyme Funktion:

<?php
$sv
= array("small", "a big string", "larger", "it is a string thing");
echo
"Original:\n";
print_r($sv);
echo
"Sortiert:\n";
usort($sv, function($a,$b) { return strlen($b) - strlen($a); });
print_r($sv);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

Original:
Array
(
  [0] => small
  [1] => a big string
  [2] => larger
  [3] => it is a string thing
)
Sortiert:
Array
(
  [0] => it is a string thing
  [1] => a big string
  [2] => larger
  [3] => small
)

Siehe auch

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