PHPのお勉強!

PHP TOP

無名関数

無名関数はクロージャとも呼ばれ、 関数名を指定せずに関数を作成できるようにするものです。 コールバック パラメータとして使う際に便利ですが、用途はそれにとどまりません。

無名関数の実装には Closure クラスを使っています。

例1 無名関数の例

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return 
strtoupper($match[1]);
}, 
'hello-world');
// helloWorld と出力します
?>

クロージャは、変数の値として使用することもできます。 PHP は、そのような記述があると自動的に内部クラス Closure のインスタンスに変換します。 変数へのクロージャの代入は、他の代入と同じように記述し、 同じく最後にセミコロンをつけます。

例2 変数への無名関数の代入

<?php
$greet 
= function($name)
{
    
printf("Hello %s\r\n"$name);
};

$greet('World');
$greet('PHP');
?>

クロージャは、変数を親のスコープから引き継ぐことができます。 引き継ぐ変数は、use で渡さなければなりません。 PHP 7.1 以降は、引き継ぐ値に superglobals$this、およびパラメータと同じ名前の変数を含めてはいけません。

例3 親のスコープからの変数の引き継ぎ

<?php
$message 
'hello';

// "use" がない場合
$example = function () {
    
var_dump($message);
};
$example();

// $message を引き継ぎます
$example = function () use ($message) {
    
var_dump($message);
};
$example();

// 引き継がれた変数の値は、関数が定義された時点のものであり、
// 関数が呼ばれた時点のものではありません
$message 'world';
$example();

// $message をリセットします
$message 'hello';

// 参照渡しで引き継ぎます
$example = function () use (&$message) {
    
var_dump($message);
};
$example();

// 親のスコープで変更された値が、
// 関数呼び出しの内部にも反映されます
$message 'world';
$example();

// クロージャは、通常の引数も受け付けます
$example = function ($arg) use ($message) {
    
var_dump($arg ' ' $message);
};
$example("hello");
?>

上の例の出力は、 たとえば以下のようになります。

Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"

親のスコープからの変数の引き継ぎは、グローバル変数を使うのとは 異なります。グローバル変数は、 関数が実行されるかどうかにかかわらずグローバルスコープに存在します。 クロージャの親スコープは、クロージャが宣言されている関数です (関数の呼び出し元のスコープである必要はありません)。 次の例を参照ください。

例4 クロージャのスコープ

<?php
// 基本的なショッピングカートで、追加した商品の一覧や各商品の
// 数量を表示します。カート内の商品の合計金額を計算するメソッド
// では、クロージャをコールバックとして使用します。
class Cart
{
    const 
PRICE_BUTTER  1.00;
    const 
PRICE_MILK    3.00;
    const 
PRICE_EGGS    6.95;

    protected 
$products = array();
    
    public function 
add($product$quantity)
    {
        
$this->products[$product] = $quantity;
    }
    
    public function 
getQuantity($product)
    {
        return isset(
$this->products[$product]) ? $this->products[$product] :
               
FALSE;
    }
    
    public function 
getTotal($tax)
    {
        
$total 0.00;
        
        
$callback =
            function (
$quantity$product) use ($tax, &$total)
            {
                
$pricePerItem constant(__CLASS__ "::PRICE_" .
                    
strtoupper($product));
                
$total += ($pricePerItem $quantity) * ($tax 1.0);
            };
        
        
array_walk($this->products$callback);
        return 
round($total2);
    }
}

$my_cart = new Cart;

// カートに商品を追加します
$my_cart->add('butter'1);
$my_cart->add('milk'3);
$my_cart->add('eggs'6);

// 合計に消費税 5% を付加した金額を表示します
print $my_cart->getTotal(0.05) . "\n";
// 結果は 54.29 です
?>

例5 $this の自動バインド

<?php

class Test
{
    public function 
testing()
    {
        return function() {
            
var_dump($this);
        };
    }
}

$object = new Test;
$function $object->testing();
$function();
    
?>

上の例の出力は以下となります。

object(Test)#1 (0) {
}

上の例の PHP 5.3 での出力は、このようになります。

Notice: Undefined variable: this in script.php on line 8
NULL

PHP 5.4.0 以降では、クラスのコンテキストで宣言した場合は現在のクラスが自動的にバインドされて、 関数のスコープで $this が使えるようになります。 現在のクラスへの自動バインドを望まない場合は、 静的無名関数 を使いましょう。

静的無名関数

PHP 5.4 以降では、静的な無名関数を宣言できるようになりました。 こうすれば、現在のクラスが無名関数を自動的にバインドすることがなくなります。 オブジェクトも、実行時にはバインドされなくなります。

例6 静的無名関数内での $this の使用例

<?php

class Foo
{
    function 
__construct()
    {
        
$func = static function() {
            
var_dump($this);
        };
        
$func();
    }
};
new 
Foo();

?>

上の例の出力は以下となります。

Notice: Undefined variable: this in %s on line %d
NULL

例7 静的無名関数へのオブジェクトのバインド

<?php

$func 
= static function() {
    
// 関数の本体
};
$func $func->bindTo(new StdClass);
$func();

?>

上の例の出力は以下となります。

Warning: Cannot bind an instance to a static closure in %s on line %d

変更履歴

バージョン 説明
7.1.0 無名関数は、superglobals や、 $this, もしくは 引数と同じ名前の変数を use で引き継げなくなりました。
5.4.0 無名関数で、静的に宣言したときのように $this を使えるようになりました。
5.3.0 無名関数が使えるようになりました。

注意

注意: クロージャ内から func_num_args()func_get_arg() および func_get_args() を使用することができます。

add a note add a note

User Contributed Notes 40 notes

up
267
orls
10 years ago
Watch out when 'importing' variables to a closure's scope  -- it's easy to miss / forget that they are actually being *copied* into the closure's scope, rather than just being made available.

So you will need to explicitly pass them in by reference if your closure cares about their contents over time:

<?php
$result
= 0;

$one = function()
{
var_dump($result); };

$two = function() use ($result)
{
var_dump($result); };

$three = function() use (&$result)
{
var_dump($result); };

$result++;

$one();    // outputs NULL: $result is not in scope
$two();    // outputs int(0): $result was copied
$three();    // outputs int(1)
?>

Another less trivial example with objects (what I actually tripped up on):

<?php
//set up variable in advance
$myInstance = null;

$broken = function() uses ($myInstance)
{
    if(!empty(
$myInstance)) $myInstance->doSomething();
};

$working = function() uses (&$myInstance)
{
    if(!empty(
$myInstance)) $myInstance->doSomething();
}

//$myInstance might be instantiated, might not be
if(SomeBusinessLogic::worked() == true)
{
   
$myInstance = new myClass();
}

$broken();    // will never do anything: $myInstance will ALWAYS be null inside this closure.
$working();    // will call doSomething if $myInstance is instantiated

?>
up
112
mike at blueroot dot co dot uk
10 years ago
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
}
?>
up
6
dexen dot devries at gmail dot com
2 years ago
Every instance of a lambda has own instance of static variables. This provides for great event handlers, accumulators, etc., etc.

Creating new lambda with function() { ... }; expression creates new instance of its static variables. Assigning a lambda to a variable does not create a new instance. A lambda is object of class Closure, and assigning lambdas to variables has the same semantics as assigning object instance to variables.

Example script: $a and $b have separate instances of static variables, thus produce different output. However $b and $c share their instance of static variables - because $c is refers to the same object of class Closure as $b - thus produce the same output.

#!/usr/bin/env php
<?php

function generate_lambda() : Closure
{
       
# creates new instance of lambda
   
return function($v = null) {
        static
$stored;
        if (
$v !== null)
           
$stored = $v;
        return
$stored;
    };
}

$a = generate_lambda();  # creates new instance of statics
$b = generate_lambda();  # creates new instance of statics
$c = $b;                                 # uses the same instance of statics as $b

$a('test AAA');
$b('test BBB');
$c('test CCC');  # this overwrites content held by $b, because it refers to the same object

var_dump([ $a(), $b(), $c() ]);
?>

This test script outputs:
array(3) {
  [0]=>
  string(8) "test AAA"
  [1]=>
  string(8) "test CCC"
  [2]=>
  string(8) "test CCC"
}
up
61
fabiolimasouto at gmail dot com
9 years ago
You may have been disapointed if you tried to call a closure stored in an instance variable as you would regularly do with methods:

<?php

$obj
= new StdClass();

$obj->func = function(){
echo
"hello";
};

//$obj->func(); // doesn't work! php tries to match an instance method called "func" that is not defined in the original class' signature

// you have to do this instead:
$func = $obj->func;
$func();

// or:
call_user_func($obj->func);

// however, you might wanna check this out:
$array['func'] = function(){
echo
"hello";
};

$array['func'](); // it works! i discovered that just recently ;)
?>

Now, coming back to the problem of assigning functions/methods "on the fly" to an object and being able to call them as if they were regular methods, you could trick php with this lawbreaker-code:

<?php
class test{
private
$functions = array();
private
$vars = array();

function
__set($name,$data)
{
  if(
is_callable($data))
   
$this->functions[$name] = $data;
  else
  
$this->vars[$name] = $data;
}

function
__get($name)
{
  if(isset(
$this->vars[$name]))
   return
$this->vars[$name];
}

function
__call($method,$args)
{
  if(isset(
$this->functions[$method]))
  {
  
call_user_func_array($this->functions[$method],$args);
  } else {
  
// error out
 
}
}
}

// LET'S BREAK SOME LAW NOW!
$obj = new test;

$obj->sayHelloWithMyName = function($name){
echo
"Hello $name!";
};

$obj->sayHelloWithMyName('Fabio'); // Hello Fabio!

// THE OLD WAY (NON-CLOSURE) ALSO WORKS:

function sayHello()
{
echo
"Hello!";
}

$obj->justSayHello = 'sayHello';
$obj->justSayHello(); // Hello!
?>

NOTICE: of course this is very bad practice since you cannot refere to protected or private fields/methods inside these pseudo "methods" as they are not instance methods at all but rather ordinary functions/closures assigned to the object's instance variables "on the fly". But I hope you've enjoyed the jurney ;)
up
10
toonitw at gmail dot com
2 years ago
As of PHP 7.0, you can use IIFE(Immediately-invoked function expression) by wrapping your anonymous function with ().

<?php
$type
= 'number';
var_dump( ...( function() use ($type) {
    if (
$type=='number') return [1,2,3];
    else if (
$type=='alphabet') return ['a','b','c'];
} )() );
?>
up
24
cHao
6 years ago
In case you were wondering (cause i was), anonymous functions can return references just like named functions can.  Simply use the & the same way you would for a named function...right after the `function` keyword (and right before the nonexistent name).

<?php
    $value
= 0;
   
$fn = function &() use (&$value) { return $value; };

   
$x =& $fn();
   
var_dump($x, $value);        // 'int(0)', 'int(0)'
   
++$x;
   
var_dump($x, $value);        // 'int(1)', 'int(1)'
up
23
erolmon dot kskn at gmail dot com
5 years ago
<?php
   
/*
    (string) $name Name of the function that you will add to class.
    Usage : $Foo->add(function(){},$name);
    This will add a public function in Foo Class.
    */
   
class Foo
   
{
        public function
add($func,$name)
        {
           
$this->{$name} = $func;
        }
        public function
__call($func,$arguments){
           
call_user_func_array($this->{$func}, $arguments);
        }
    }
   
$Foo = new Foo();
   
$Foo->add(function(){
        echo
"Hello World";
    },
"helloWorldFunction");
   
$Foo->add(function($parameterone){
        echo
$parameterone;
    },
"exampleFunction");
   
$Foo->helloWorldFunction(); /*Output : Hello World*/
   
$Foo->exampleFunction("Hello PHP"); /*Output : Hello PHP*/
?>
up
12
Anonymous
3 years ago
If you want to create and then immediately call a closure directly, in-line, and immediately get its return value (instead of the closure reference itself), then the proper syntax is as follows:

<?php

$a
= 'foo'; $b = 'bar';
$test = (function() use($a,$b) { return $a . $b; })();
echo
$test;

?>

As for why you would want to do that? Well, that's up to you. I'm sure there are some legitimate reasons. It's a pretty common pattern in some other famous scripting languages. But if you're doing this in PHP, you should think carefully and ask yourself if you really have a good reason for it, or if you should just go and re-structure your code instead. ;-)
up
13
housni dot yakoob at gmail dot com
10 years ago
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) ""
 
}
}
?>
up
6
rob at ubrio dot us
10 years ago
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();

?>
up
11
a dot schaffhirt at sedna-soft dot de
11 years ago
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,
up
11
Hayley Watson
9 years ago
As an alternative to gabriel's recursive construction, you may instead assign the recursive function to a variable, and use it by reference, thus:

<?php
$fib
= function($n)use(&$fib)
{
    if(
$n == 0 || $n == 1) return 1;
    return
$fib($n - 1) + $fib($n - 2);
};

echo
$fib(10);
?>
Hardly a sensible implementation of the Fibonacci sequence, but that's not the point! The point is that the variable needs to be used by reference, not value.

Without the '&', the anonymous function gets the value of $fib at the time the function is being created. But until the function has been created, $fib can't have it as a value! It's not until AFTER the function has been assigned to $fib that $fib can be used to call the function - but by then it's too late to pass its value to the function being created!

Using a reference resolves the dilemma: when called, the anonymous function will use $fib's current value, which will be the anonymous function itself.

At least, it will be if you don't reassign $fib to anything else between creating the function and calling it:

<?php
$fib
= function($n)use(&$fib)
{
    if(
$n == 0 || $n == 1) return 1;
    return
$fib($n - 1) + $fib($n - 2);
};

$lie = $fib;

$fib = function($n)
{
    return
100;
};

echo
$lie(10); // 200, because $fib(10 - 1) and $fib(10 - 2) both return 100.
?>

Of course, that's true of any variable: if you don't want its value to change, don't change its value.

All the usual scoping rules for variables still apply: a local variable in a function is a different variable from another one with the same name in another function:

<?php
$fib
= function($n)use(&$fib)
{
    if(
$n == 0 || $n == 1) return 1;
    return
$fib($n - 1) + $fib($n - 2);
};

$bark = function($f)
{
   
$fib = 'cake';    // A totally different variable from the $fib above.
   
return 2 * $f(5);
};

echo
$bark($fib); // 16, twice the fifth Fibonacci number

?>
up
13
john at binkmail dot com
3 years ago
PERFORMANCE BENCHMARK 2017!

I decided to compare a single, saved closure against constantly creating the same anonymous closure on every loop iteration. And I tried 10 million loop iterations, in PHP 7.0.14 from Dec 2016. Result:

a single saved closure kept in a variable and re-used (10000000 iterations): 1.3874590396881 seconds

new anonymous closure created each time (10000000 iterations): 2.8460240364075 seconds

In other words, over the course of 10 million iterations, creating the closure again during every iteration only added a total of "1.459 seconds" to the runtime. So that means that every creation of a new anonymous closure takes about 146 nanoseconds on my 7 years old dual-core laptop. I guess PHP keeps a cached "template" for the anonymous function and therefore doesn't need much time to create a new instance of the closure!

So you do NOT have to worry about constantly re-creating your anonymous closures over and over again in tight loops! At least not as of PHP 7! There is absolutely NO need to save an instance in a variable and re-use it. And not being restricted by that is a great thing, because it means you can feel free to use anonymous functions exactly where they matter, as opposed to defining them somewhere else in the code. :-)
up
6
jigar
4 years ago
Will result in a "Parse error: syntax error, unexpected '[', expecting ',' or ')' ... "

<?php

$fruits
= ['apples', 'oranges'];
$example = function () use ($fruits[0]) {
    echo
$fruits[0];
};
$example();
?>

Would have to do this:

<?php

$fruits
= ['apples', 'oranges'];
$example = function () use ($fruits) {
    echo
$fruits[0]; // will echo 'apples'
};
$example();

?>

Or this instead:

<?php

$fruits
= ['apples', 'oranges'];
$fruit = $fruits[0];
$example = function () use ($fruit) {
    echo
$fruit; // will echo 'apples'
};
$example();
up
5
rmckay at webaware dot com dot au
6 years ago
Some hosts are installing the eAccelerator opcode cache with PHP 5.4, and current production versions of this opcode cache break closures. If you find that your nice, working closures break when you load your code to a hosted website, check for eAccelerator (e.g. by calling phpinfo() and checking the output).

Simple fixes include:

* disabling eAccelerator and opcode caching
* replacing eAccelerator with Zend's opcache
* reverting to PHP 5.3

Apparently, the eAccelerator project has solved this issue, but hosts move slowly so I recommend removing eAccelerator from the equation for now.
up
1
jake dot tunaley at berkeleyit dot com
1 year ago
Beware of using $this in anonymous functions assigned to a static variable.

<?php
class Foo {
    public function
bar() {
        static
$anonymous = null;
        if (
$anonymous === null) {
           
// Expression is not allowed as static initializer workaround
           
$anonymous = function () {
                return
$this;
            };
        }
        return
$anonymous();
    }
}

$a = new Foo();
$b = new Foo();
var_dump($a->bar() === $a); // True
var_dump($b->bar() === $a); // Also true
?>

In a static anonymous function, $this will be the value of whatever object instance that method was called on first.

To get the behaviour you're probably expecting, you need to pass the $this context into the function.

<?php
class Foo {
    public function
bar() {
        static
$anonymous = null;
        if (
$anonymous === null) {
           
// Expression is not allowed as static initializer workaround
           
$anonymous = function (self $thisObj) {
                return
$thisObj;
            };
        }
        return
$anonymous($this);
    }
}

$a = new Foo();
$b = new Foo();
var_dump($a->bar() === $a); // True
var_dump($b->bar() === $a); // False
?>
up
4
gabriel dot totoliciu at ddsec dot net
10 years ago
If you want to make a recursive closure, you will need to write this:

$some_var1="1";
$some_var2="2";

function($param1, $param2) use ($some_var1, $some_var2)
{

//some code here

call_user_func(__FUNCTION__, $other_param1, $other_param2);

//some code here

}

If you need to pass values by reference you should check out

http://www.php.net/manual/en/function.call-user-func.php
http://www.php.net/manual/en/function.call-user-func-array.php

If you're wondering if $some_var1 and $some_var2 are still visible by using the call_user_func, yes, they are available.
up
3
derkontrollfreak+9hy5l at gmail dot com
6 years ago
Beware that since PHP 5.4 registering a Closure as an object property that has been instantiated in the same object scope will create a circular reference which prevents immediate object destruction:
<?php

class Test
{
    private
$closure;

    public function
__construct()
    {
       
$this->closure = function () {
        };
    }

    public function
__destruct()
    {
        echo
"destructed\n";
    }
}

new
Test;
echo
"finished\n";

/*
* Result in PHP 5.3:
* ------------------
* destructed
* finished
*
* Result since PHP 5.4:
* ---------------------
* finished
* destructed
*/

?>

To circumvent this, you can instantiate the Closure in a static method:
<?php

public function __construct()
{
   
$this->closure = self::createClosure();
}

public static function
createClosure()
{
    return function () {
    };
}

?>
up
6
ldrut
9 years ago
A common way to avoid contaminating Javascript global space with unneeded variables is to move the code into an immediately called anonymous closure.

(function(){ ... })()

The equivalent way to do that in PHP 5.3+ is

call_user_func(function() use(closure-vars){ ... });
up
12
aaron at afloorabove dot com
10 years ago
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()
*/

?>