If you want to make sure that one of the parameters of your function is a Closure, you can use Type Hinting.
see: http://php.net/manual/en/language.oop5.typehinting.php
Example:
<?php
class TheRoot
{
public function poidh($param) {
echo "TheRoot $param!";
}
}
class Internet
{
# here, $my_closure must be of type object Closure
public function run_my_closure($bar, Closure $my_closure) {
$my_closure($bar);
}
}
$Internet = new Internet();
$Root = new TheRoot();
$Internet->run_my_closure($Root, function($Object) {
$Object->poidh(42);
});
?>
The above code simply yields:
"TheRoot 42!"
NOTE: If you are using namespaces, make sure you give a fully qualified namespace.
print_r() of Internet::run_my_closure's $my_closure
<?php
Closure Object
(
[parameter] => Array
(
[$Object] =>
)
)
?>
var_dump() of Internet::run_my_closure's $my_closure
<?php
object(Closure)#3 (1) {
["parameter"]=>
array(1) {
["$Object"]=>
string(10) ""
}
}
?>
익명 함수
익명 함수는 이름을 지정하지 않은 함수를 생성할 수 있게 합니다. 콜백 인수에 매우 유용하나, 다른 용도로 사용할 수도 있습니다.
Example #1 익명 함수 예제
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// 출력: helloWorld
?>
익명 함수는 내부적으로 Closure 클래스로 구현됩니다.
Note: 익명 함수는 PHP 5.3.0부터 사용할 수 있습니다.
익명 함수
housni dot yakoob at gmail dot com
14-Mar-2010 05:22
14-Mar-2010 05:22
aaron at afloorabove dot com
05-Mar-2010 10:42
05-Mar-2010 10:42
Anonymous functions are great for events!
<?php
class Event {
public static $events = array();
public static function bind($event, $callback, $obj = null) {
if (!self::$events[$event]) {
self::$events[$event] = array();
}
self::$events[$event][] = ($obj === null) ? $callback : array($obj, $callback);
}
public static function run($event) {
if (!self::$events[$event]) return;
foreach (self::$events[$event] as $callback) {
if (call_user_func($callback) === false) break;
}
}
}
function hello() {
echo "Hello from function hello()\n";
}
class Foo {
function hello() {
echo "Hello from foo->hello()\n";
}
}
class Bar {
function hello() {
echo "Hello from Bar::hello()\n";
}
}
$foo = new Foo();
// bind a global function to the 'test' event
Event::bind("test", "hello");
// bind an anonymous function
Event::bind("test", function() { echo "Hello from anonymous function\n"; });
// bind an class function on an instance
Event::bind("test", "hello", $foo);
// bind a static class function
Event::bind("test", "Bar::hello");
Event::run("test");
/* Output
Hello from function hello()
Hello from anonymous function
Hello from foo->hello()
Hello from Bar::hello()
*/
?>
ljackson at jjcons dot com
22-Feb-2010 06:46
22-Feb-2010 06:46
appears kwilson at shuttlebox dot net that you may have just made unintended side effect. Note that adding the global $variable to your test function make the closure function echo second rather than first So the anonymous function works as expected with respect to globals.
<?php
$variable = "first";
$closure = function() {
global $variable;
echo $variable . "\n";
};
$closure();
function test($closure)
{
global $variable; //Note the scope added here
$variable = "second";
$closure();
}
test($closure);
?>
prints:
first
second
tested with php 5.3.1
kwilson at shuttlebox dot net
21-Jan-2010 03:24
21-Jan-2010 03:24
Using the global keyword apparently pulls variables from the scope where the function was created, not where it is executed.
Example:
<?php
$variable = "first";
$closure = function() {
global $variable;
echo $variable . "\n";
};
$closure();
function test($closure)
{
$variable = "second";
$closure();
}
test($closure);
?>
Will print:
first
first
puskulcu at gmail dot com
14-Dec-2009 08:46
14-Dec-2009 08:46
hello there!
here is a little code which shows use of the closures as event handlers:
<?php
class Button
{
public $OnBeforeClick;
public $OnAfterClick;
public $Name;
function Button()
{
$this->Name = 'MyButton';
}
public function Click()
{
$this->DoBeforeClick();
echo 'Click!';
$this->DoAfterClick();
}
private function DoBeforeClick()
{
if (isset($this->OnBeforeClick))
{
$Event = $this->OnBeforeClick;
$Event($this);
}
}
private function DoAfterClick()
{
if (isset($this->OnAfterClick))
{
$Event = $this->OnAfterClick;
$Event($this);
}
}
}
//eclipse may warn here about syntax error but no problem, it runs well.
$BeforeClickEventHandler = function($Sender) { echo $Sender->Name . ' (Before Click)'; };
$AfterClickEventHandler = function($Sender) { echo $Sender->Name . ' (After Click)'; };
$MyWidget = new Button();
$MyWidget->OnBeforeClick = $BeforeClickEventHandler;
$MyWidget->OnAfterClick = $AfterClickEventHandler;
$MyWidget->Click();
?>
output:
MyButton (Before Click)
Click!
MyButton (After Click)
i hope you find this useful.
regards.
emre
rob at ubrio dot us
25-Nov-2009 06:20
25-Nov-2009 06:20
You can always call protected members using the __call() method - similar to how you hack around this in Ruby using send.
<?php
class Fun
{
protected function debug($message)
{
echo "DEBUG: $message\n";
}
public function yield_something($callback)
{
return $callback("Soemthing!!");
}
public function having_fun()
{
$self =& $this;
return $this->yield_something(function($data) use (&$self)
{
$self->debug("Doing stuff to the data");
// do something with $data
$self->debug("Finished doing stuff with the data.");
});
}
// Ah-Ha!
public function __call($method, $args = array())
{
if(is_callable(array($this, $method)))
return call_user_func_array(array($this, $method), $args);
}
}
$fun = new Fun();
echo $fun->having_fun();
?>
mike at blueroot dot co dot uk
28-Oct-2009 04:40
28-Oct-2009 04:40
To recursively call a closure, use this code.
<?php
$recursive = function () use (&$recursive){
// The function is now available as $recursive
}
?>
This DOES NOT WORK
<?php
$recursive = function () use ($recursive){
// The function is now available as $recursive
}
?>
kukoman at pobox dot sk
13-Oct-2009 12:22
13-Oct-2009 12:22
be aware of Fatal error: Using $this when not in object context when using in closures
http://wiki.php.net/rfc/closures/removal-of-this
gerard at visei dot nl
07-Oct-2009 02:41
07-Oct-2009 02:41
The text above the third example tries to explain that anonymous functions can inherit variables from the parent scope, but fails to properly explain how this is done: namely using the "use" keyword in the function definition.
The following page has a much more detailed explanation of closures in PHP 5.3:
http://wiki.php.net/rfc/closures
andrew at evilwalr dot us
03-Oct-2009 05:06
03-Oct-2009 05:06
Very easy way to get the netstat (windows)... yes, this could be a function, but as an example, here it is in closure form...
<?php
$netstat = function($return = null, $precision = 2) {
// supplement function
$_convert = function ($bytes) use ($precision) {
$i = 0; $iec = array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb');
while (($bytes / 1024) > 1): $bytes = $bytes / 1024; $i++; endwhile;
return round(substr($bytes, 0, strpos($bytes, '.') + 4), $precision) . ' ' . strtoupper($iec[$i]);
};
foreach (explode("\n", `netstat -e`) as $d) {
if (preg_match('/^Bytes([\s].+)([0-9])([\s].+)([0-9])/', $d, $m)) {
switch ($return) {
case 'sent': return $_convert(trim($m[1].$m[2])); break;
case 'recv': return $_convert(trim($m[3].$m[4])); break;
default: return array('sent' => $_convert(trim($m[1].$m[2])),
'recv' => $_convert(trim($m[3].$m[4]))); break;
}
}
}
};
?>
Jaakko Salmela
09-Sep-2009 10:52
09-Sep-2009 10:52
<?php
/**
* Using closures to dynamically extend objects
*
*/
class ClosureTest{
public $member = 'test';
protected $protectedMember = 'protectedtest';
public function __call($method, $args)
{
return call_user_func_array( $this->$method, $args);
}
}
$object = new ClosureTest();
$object->closure = function() use ($object){
return $object->member;
};
echo $object->closure();
//Output: 'test'
/**
* This won't work, you can not access protected/private members, which is fine.
*/
$object->closureAccessProtected = function() use ($object){
return $object->protectedMember;
};
$object->closureAccessProtected();
?>
dave at mausner dot us
10-Aug-2009 09:34
10-Aug-2009 09:34
Ulderico had it almost right. To avoid confusing the interpreter, when using a simple closure stored in a $variable, you must invoke the nameless function using the function syntax.
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld( );
?>
Note the empty actual-parameter list in the "echo". NOW IT WORKS.
Anonymous
03-Aug-2009 09:50
03-Aug-2009 09:50
If you want to check whether you're dealing with a closure specifically and not a string or array callback you can do this:
<?php
$isAClosure = is_callable($thing) && is_object($thing);
?>
tom at r dot je
29-Jul-2009 10:51
29-Jul-2009 10:51
Unfortunately, you can't get a pointer to a function, the only function pointers are ones which use anonymous functions as they're created.
This wont work:
<?php
$info = phpinfo;
$info();
//or
function foo() {
echo 'bar';
}
$foo = foo;
$foo();
?>
Because of the behavior of $foo(), it will assume $foo is a string, and try to run the function with the name stored in the string.
ulderico at maber dot com dot br
14-Jul-2009 02:43
14-Jul-2009 02:43
Perhaps you'll find yourself wanting doing a wicked thing like:
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld;
?>
which throws:
Catchable fatal error: Object of class String could not be converted to string
OK... Here's the way of doing this.
<?php
class Helloworld{
function __toString(){
return("each hello world is different...".date("His"));
}
}
$helloworld = new Helloworld();
echo $helloworld;
sleep(5);
echo $helloworld;
?>
mcm dot matt at gmail dot com
30-Jun-2009 12:49
30-Jun-2009 12:49
Example using uasort.
<?php
// Usual method.
function cmp($a, $b) {
return($a > $b);
}
uasort($array, 'cmp');
// New
uasort($array, function($a, $b) {
return($a > $b);
});
?>
a dot schaffhirt at sedna-soft dot de
19-Jun-2009 09:55
19-Jun-2009 09:55
When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.
Consider the following example:
<?php
class MyClass {
const member = 1;
public $member;
public function member () {
return "method 'member'";
}
public function __construct () {
$this->member = function () {
return "anonymous function 'member'";
};
}
}
header("Content-Type: text/plain");
$myObj = new MyClass();
var_dump(MyClass::member); // int(1)
var_dump($myObj->member); // object(Closure)#2 (0) {}
var_dump($myObj->member()); // string(15) "method 'member'"
$myMember = $myObj->member;
var_dump($myMember()); // string(27) "anonymous function 'member'"
?>
That means, regular method invocations work like expected and like before. The anonymous function instead, must be retrieved into a variable first (just like a property) and can only then be invoked.
Best regards,
