無名関数
無名関数はクロージャ
とも呼ばれ、
関数名を指定せずに関数を作成できるようにするものです。
callable
パラメータとして使う際に便利ですが、用途はそれにとどまりません。
例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 以降は、引き継ぐ値に スーパーグローバル や
$this、
およびパラメータと同じ名前の変数を含めてはいけません。
戻り値の型は、
use
の 後
に置かなければいけません。
例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");
// 戻り値の型は、use の後に置きます
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
上の例の出力は、 たとえば以下のようになります。
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" string(11) "hello world"
PHP 8.0.0 以降では、親のスコープを継承した変数の一覧の最後にカンマを付けられるようになりました。 このカンマは無視されます。
親のスコープからの変数の引き継ぎは、グローバル変数を使うのとは 異なります。グローバル変数は、 関数が実行されるかどうかにかかわらずグローバルスコープに存在します。 クロージャの親スコープは、クロージャが宣言されている関数です (関数の呼び出し元のスコープである必要はありません)。 次の例を参照ください。
例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($total, 2);
}
}
$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) { }
クラスのコンテキストで宣言した場合は、現在のクラスが自動的にバインドされて、
関数のスコープで $this
が使えるようになります。
現在のクラスへの自動バインドを望まない場合は、
static な無名関数
を使いましょう。
static な無名関数
static を付けて無名関数を宣言することができます。 こうすることで、現在のクラスが無名関数を自動的にバインドすることがなくなります。 オブジェクトも、実行時にはバインドされなくなります。
例6 static な無名関数内での $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 static な無名関数へのオブジェクトのバインド
<?php
$func = static function() {
// 関数の本体
};
$func = $func->bindTo(new stdClass);
$func();
?>
上の例の出力は以下となります。
Warning: Cannot bind an instance to a static closure in %s on line %d
注意
注意: クロージャ内から func_num_args()、 func_get_arg() および func_get_args() を使用することができます。
User Contributed Notes 20 notes
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
?>
<?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*/
?>
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)'
If you have a closure (or other callable) stored in an object property and you want to call it, you can use parentheses to disambiguate between it and a method call:
<?php
class Test
{
public $callable;
function __construct()
{
$this->callable = function($a) { return $a + 2; };
}
}
$t = new Test;
echo ($t->callable)(40);
?>
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"
}
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,
One way to call a anonymous function recursively is to use the USE keyword and pass a reference to the function itself:
<?php
$count = 1;
$add = function($count) use (&$add){
$count += 1;
if($count < 10) $count = $add($count); //recursive calling
return $count;
};
echo $add($count); //Will output 10 as expected
?>
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();
?>
Some comparisons of PHP and JavaScript closures.
=== Example 1 (passing by value) ===
PHP code:
<?php
$aaa = 111;
$func = function() use($aaa){ print $aaa; };
$aaa = 222;
$func(); // Outputs "111"
?>
Similar JavaScript code:
<script type="text/javascript">
var aaa = 111;
var func = (function(aaa){ return function(){ alert(aaa); } })(aaa);
aaa = 222;
func(); // Outputs "111"
</script>
Be careful, following code is not similar to previous code:
<script type="text/javascript">
var aaa = 111;
var bbb = aaa;
var func = function(){ alert(bbb); };
aaa = 222;
func(); // Outputs "111", but only while "bbb" is not changed after function declaration
// And this technique is not working in loops:
var functions = [];
for (var i = 0; i < 2; i++)
{
var i2 = i;
functions.push(function(){ alert(i2); });
}
functions[0](); // Outputs "1", wrong!
functions[1](); // Outputs "1", ok
</script>
=== Example 2 (passing by reference) ===
PHP code:
<?php
$aaa = 111;
$func = function() use(&$aaa){ print $aaa; };
$aaa = 222;
$func(); // Outputs "222"
?>
Similar JavaScript code:
<script type="text/javascript">
var aaa = 111;
var func = function(){ alert(aaa); };
aaa = 222; // Outputs "222"
func();
</script>
<?php
/*
* An example showing how to use closures to implement a Python-like decorator
* pattern.
*
* My goal was that you should be able to decorate a function with any
* other function, then call the decorated function directly:
*
* Define function: $foo = function($a, $b, $c, ...) {...}
* Define decorator: $decorator = function($func) {...}
* Decorate it: $foo = $decorator($foo)
* Call it: $foo($a, $b, $c, ...)
*
* This example show an authentication decorator for a service, using a simple
* mock session and mock service.
*/
session_start();
/*
* Define an example decorator. A decorator function should take the form:
* $decorator = function($func) {
* return function() use $func) {
* // Do something, then call the decorated function when needed:
* $args = func_get_args($func);
* call_user_func_array($func, $args);
* // Do something else.
* };
* };
*/
$authorise = function($func) {
return function() use ($func) {
if ($_SESSION['is_authorised'] == true) {
$args = func_get_args($func);
call_user_func_array($func, $args);
}
else {
echo "Access Denied";
}
};
};
/*
* Define a function to be decorated, in this example a mock service that
* need to be authorised.
*/
$service = function($foo) {
echo "Service returns: $foo";
};
/*
* Decorate it. Ensure you replace the origin function reference with the
* decorated function; ie just $authorise($service) won't work, so do
* $service = $authorise($service)
*/
$service = $authorise($service);
/*
* Establish mock authorisation, call the service; should get
* 'Service returns: test 1'.
*/
$_SESSION['is_authorised'] = true;
$service('test 1');
/*
* Remove mock authorisation, call the service; should get 'Access Denied'.
*/
$_SESSION['is_authorised'] = false;
$service('test 2');
?>
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. :-)
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 () {
};
}
?>
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'];
} )() );
?>