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.(PHP 4 >= 4.0.1, PHP 5, PHP 7)
create_function β Π‘ΠΎΠ·Π΄Π°ΡΡ ΡΡΠ½ΠΊΡΠΈΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ, ΠΎΡΠ΅Π½ΠΈΠ²Π°Ρ ΡΡΡΠΎΠΊΡ ΠΊΠΎΠ΄Π°
ΠΠ°ΡΠΈΠ½Π°Ρ Ρ PHP 7.2.0 ΡΡΠ½ΠΊΡΠΈΡ Π£Π‘Π’ΠΠ ΠΠΠ, Π° Π² PHP 8.0.0 ΡΡΠ½ΠΊΡΠΈΡ Π£ΠΠΠΠΠΠ. ΠΠΎΠ»Π°Π³Π°ΡΡΡΡ Π½Π° ΡΡΠ½ΠΊΡΠΈΡ Π½Π°ΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ Π½Π΅ ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡΡΡ.
Π‘ΠΎΠ·Π΄Π°ΡΡ ΡΡΠ½ΠΊΡΠΈΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ ΠΈΠ· ΠΏΠ΅ΡΠ΅Π΄Π°Π½Π½ΡΡ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΠΈ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ Π΅Ρ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΠΎΠ΅ ΠΈΠΌΡ.
Π€ΡΠ½ΠΊΡΠΈΡ Π²Π½ΡΡΡΠΈ ΡΠ΅Π±Ρ Π΄Π΅Π»Π°Π΅Ρ Π²ΡΠ·ΠΎΠ² ΡΡΠ½ΠΊΡΠΈΠΈ 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] => ΠΌΠ°Π»ΠΎ
)
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.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.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);
?>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;
}
?>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.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
?>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;
}
?>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".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
?>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
?>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);
}
}');
?>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.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;
}
?>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).[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);
}
}
?>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];
}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...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');
?>$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.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
?>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.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.