downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

クラスとオブジェクト> <内部(ビルトイン)関数
Last updated: Fri, 13 Nov 2009

view this page in

無名関数

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

例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');
?>

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

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

<?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('バター'1);
$my_cart->add('牛乳'3);
$my_cart->add('卵'6);

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

無名関数は、現在は Closure クラスで実装されています。 これはあくまでも内部実装の問題であり、この事実に依存したコードを書いてはいけません。

注意: 無名関数は PHP 5.3.0 以降で使用可能です。

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



add a note add a note User Contributed Notes
無名関数
mike at blueroot dot co dot uk
29-Oct-2009 01: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 09: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 11: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 02: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 07: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
11-Aug-2009 06: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 06: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 07: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 11: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 09: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 06: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,

 
show source | credits | stats | sitemap | contact | advertising | mirror sites