7

私は、クロージャーを介して機能を拡張する jQuery/Javascript の方法を気に入っています。PHP 5.3で同様のことを行うことは可能ですか?

class Foo
{
    public $bar;
}

$foo = new Foo;
$foo->bar = function($baz) { echo strtoupper($baz); };
$foo->bar('lorem ipsum dolor sit amet');
// LOREM IPSUM DOLOR SIT AMET

[編集] 私の質問で「それ」と「である」を混同しました。へー。

アップデート

5.3a3 をダウンロードしましたが、動作します。

class Foo
{
    protected $bar;
    public $baz;

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

    public function __call($method, $args)
    {
        $closure = $this->$method;
        call_user_func_array($closure, $args);
    }

}

$foo = new Foo(function($name) { echo "Hello, $name!\n"; });
$foo->bar('Mon'); 
// Hello, Mon!
$foo->baz = function($s) { echo strtoupper($s); };
$foo->baz('the quick brown fox jumps over the lazy dog');
// THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
4

7 に答える 7

4

PHP 5.3 では、コード例を実装できるラムダ関数とクロージャーを作成できます。PHP RFCから:

function & (parameters) use (lexical vars) { body }

関数は参照として返され、コールバックとして渡すことができます。たとえば、次の関数を作成します。

$lambda = function () { echo "Hello World!\n"; };

ラムダ関数をコールバックとして渡す:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

クロージャーを使用すると、ローカル スコープから変数をインポートすることもできます。

$map = function ($text) use ($search, $replacement) {
    if (strpos ($text, $search) > 50) {
       return str_replace ($search, $replacement, $text);
    } else {
        return $text;
    }
};

$search と $replacement は両方ともクロージャの外で宣言され、$text は関数パラメータです。

于 2009-01-07T11:12:54.030 に答える
1

適切な無名関数 / クロージャは、PHP 5.3 でのみ利用可能です。これは、しばらくの間、広く利用できなくなります -いくつかの有用な情報. あなたがやりたいことをすることは本当に可能だとは思いません。

create_function()ある程度使用できます:

$func = create_function('$baz', ' echo strtoupper($baz); ');
$func("hello");

ただし、以下は期待どおりに機能しません。

$foo = new Foo;
$foo->bar = create_function('$baz', ' echo strtoupper($baz); ');
$foo->bar('lorem ipsum dolor sit amet');

代わりに次のことを行う必要があります。

call_user_func($foo->bar, 'lorem ipsum dolor sit amet');

$thisまた、そのスコープはメソッドと同じではないため、作成された関数内では使用できません。

編集

私が私のものを書いている間にMartijnの回答を編集したため、誤ってMartijnの回答の一部を複製してしまいました. 完全を期すために、回答をそのままにしておきます

別の編集

あなたは多分また何かをすることができます

class Foo
{
    public $bar;

    protected $anonFuncs = array();

    public function create_method($name, $params, $code) {
        if (strlen($params)) $params .= ',';
        $params .= '$self';
        $this->anonFuncs[$name] = create_function($params, $code);
    }

    public function __call($name, $args) {
        if (!isset($this->anonFuncs[$name])) {
            trigger_error("No method $name", E_USER_ERROR);
        }

        $args[] = $this;

        return call_user_func_array($this->anonFuncs[$name], $args);
    }
}

$foo = new Foo;
$foo->create_method('bar', '$baz', ' echo strtoupper($baz) . get_class($self); ');
$foo->bar('lorem ipsum dolor sit amet');
于 2009-01-07T10:52:42.977 に答える
0

PHP5.4 リリース以降、さらに多くのことができるようになりました。

  1. メソッドをオブジェクトに動的に追加する
  2. これらのメソッド内で$thisを使用します
  3. ある動的オブジェクトを別の動的オブジェクトから継承する

基本的なアイデアはここで実装されています: https://github.com/ptrofimov/jslikeobject

于 2013-01-10T07:11:30.250 に答える
0

私は自分の仕事でこの create_closure() を使用して、コールバックをクラスに分離します。

<?php
function create_closure($fun, $args, $uses)
         {$params=explode(',', $args.','.$uses);
          $str_params='';
          foreach ($params as $v)
                  {$v=trim($v, ' &$');
                   $str_params.='\''.$v.'\'=>&$'.$v.', ';
                  }
          return "return function({$args}) use ({$uses}) {{$fun}(array({$str_params}));};";
         }
?>

例:

<?php
$loop->addPeriodicTimer(1, eval(create_closure('pop_message', '$timer', '$cache_key, $n, &$response, &$redis_client')));

function pop_message($params)
         {extract($params, EXTR_REFS);
          $redis_client->ZRANGE($cache_key, 0, $n)
                            ->then(//normal
                                   function($data) use ($cache_key, $n, &$timer, &$response, &$redis_client)
                                   {//...
                                   },
                                   //exception
                                   function ($e) use (&$timer, &$response, &$redis_client)
                                   {//...
                                   }
                                  );
         }
?>
于 2014-06-10T05:00:56.490 に答える
0

create 関数を使用すると、次のようなことができます。

$Dynamic->lambda = create_function('$var', 'return $var." world."; ');
$classic = $Dynamic->lambda("hello"); // classic would contain "hello world."

クラス コードには次のようなものが含まれます。

public function __set($methodname, $function)
{
    $this->methods[$methodname] = $function;
}

public function __get($methodname)
{
    return $this->methods[$methodname];
}

public function __call($method, $args)
{
   $funct = $this->{$method};
   //$args[] = $this; --to add the current object as a parameter option
   return call_user_func_array($funct, $args);
}

$this注:基本的にこれは、グローバル名前空間にある create_function へのオブジェクト インターフェイスを使用するだけなので、create 関数でオブジェクト スコープ (変数) を使用することはできません。ただし、オブジェクトのインスタンスをパラメーター リストに簡単に追加してクラスにプルすることはできますが、その場合も、プルされたクラスのパブリック メソッドにしかアクセスできません。

于 2009-01-08T08:49:09.497 に答える