2016-08-19 9 views
15

は、あなたがこのような機能を命名していることができクロージャから名前付き関数を作成することはできますか?</p> <pre><code>function foo() { return "bar"; } </code></pre> <p>そして、あなたはこのようにクロージャを持つことができます:PHPで

$foo = function() { 
    return "bar"; 
}; 

クロージャを作成するために素晴らしいと簡単ですが、残念ながらライブラリは私がする必要があります本当に名前付き関数が必要です。クロージャから名前付き関数を動的に作成することは可能ですか?私。コード内のすべての関数を事前に定義するのではなく、register_function($name, callable $closure)のようになります。

私はcreate_functionを認識していますが、PHP本体の文字列を関数本体として受け取り、evalという文字列を使用していますが、これは私が探しているものではありません。

+1

「名前付き関数が必要です」とはどういう意味ですか?あなたは 'library_function( 'my_func')'を実行しなければなりませんし、 'function library_function($ func){$ func(); } '? –

+0

@MarcB:そうしたいと思う。いいえ、ライブラリはSmartyで、ユースケースはプラグインを登録しています。それはあなたがそれを与えるどの種類の呼び出し可能で、現在はClosureをサポートしていないかに応じてテンプレートの特定のコンパイルを行います。インスタンスメソッド、静的メソッド、または名前付き関数のいずれかです。 –

+0

smartyは名前付きの関数を望んでいますが、名前を付けたくありませんか? – AbraCadaver

答えて

2

私はそれがその場でクロージャのうち、名前の関数を作成することが可能であるが、クラスの__call()マジックメソッドを使用している場合、あなたはこの回避策は参考になりましかもしれないと思う:

<?php 

class Foo 
{ 
    public function __call($name, $args) 
    { 
     if (isset($this->{$name})) 
      return call_user_func_array($this->{$name}, $args); 
    } 
} 

$foo = new Foo(); 
// Declaring a closure then assign it to $bar property of Foo 
$foo->bar = function() { 
    echo "bar"; 
}; 
// Call Foo method of the same name 
$foo->bar(); 
+0

これは実際には不可能であると思われ、私は単に適切なクロージャを呼び出すオブジェクトで何かを実装しました。ただし、クロージャごとに追加のオブジェクトをインスタンス化する必要がないため、ソリューションは優れています。 –

8

コールバックを使用してグローバルアレイを作成できます。このグローバル配列にregister_func($name, $callback)で追加し、call_func($name, $parameter1, $parameter2, ...)によって関数を呼び出します。

evalコールバックから名前付き関数を作成することはできません。

+0

グローバル変数と名前空間は一般的な良い方法として避けるべきです。あなたが "神"データオブジェクトを少なくともベンダーの名前空間にしなければならないならば。 –

+0

@Pheageyそれは簡単なアイデアです。私はもっ​​と良い解決策があることを知っています - 例えば、シングルトンコールバック - コンテナクラス。しかし、私はちょうど完全な解決策ではなく、草案を提示したい。 – ventaquil

+0

ああ、はい、とても良いです。ちょうど悪い習慣の習慣に入るOPを与えることを望んでいませんでした。キャリーオン:) –

2

私の提案はしています単純な関数のように呼び出すことができるので、静的メソッドを使用します。我々は

文字列(3)「バー」

4

を取得します出力時にこのコード

<?php 

class FunctionsProvider 
{ 
    protected static $closures = []; 

    public static function addClosure($name, $closure) 
    { 
     if (is_callable($closure)) { 
      static::$closures[$name] = $closure; 
     } else { 
      throw new \Exception('Closure is not callable'); 
     } 
    } 

    public static function __callStatic($name, $arguments) 
    { 
     if (array_key_exists($name, static::$closures)) {  
      return call_user_func_array(static::$closures[$name], $arguments); 
     } else { 
      throw new \Exception('Unknown method'); 
     } 
    } 
} 

//Lets prepare sample closure 
$foo = function() { 
    return "bar"; 
}; 

FunctionsProvider::addClosure('foo', $foo); 

$return = FunctionsProvider::foo(); 

var_dump($return); 

に似魔法機能__callStaticでこれをachiveすることができます私が使用して作成するために管理しましたevil eval,ReflectionClassおよびSuperClosureライブラリー。

<?php 

function register_function(string $name, Closure $closure) 
{ 
    $serializedBody = (new SuperClosure\Serializer)->serialize($closure); 

    $obj = unserialize($serializedBody); 
    $reflection = new ReflectionClass($obj); 
    $property = $reflection->getProperty('data'); 
    $property->setAccessible(true); 
    $data = $property->getValue($obj); 
    $body = preg_replace('/^function \(/', "function {$name} (", $data['code']); 

    eval($body); 
} 

$closure = function($a = 1, $b = 2, $c = 3) { 
    var_dump(compact('a', 'b', 'c')); 
}; 

register_function('test', $closure); 

var_dump(function_exists('test')); // true 

test(13, 2, 3); 
// array(3) { 
// ["a"]=> 
// int(13) 
// ["b"]=> 
// int(2) 
// ["c"]=> 
// int(3) 
// } 
+4

私は感心したり怖がったりするべきかどうかわかりません... – Andrew

1

は一言で言えば、あなたはPHPで\クロージャオブジェクトに名前を付けることはできません。

は、ここに私のコードです。

これを行うためのAPIがあると確信していますが、PHPレベルでは公開されていません。関数に名前を付けるためにUser-land PHP関数を公開するCプラグインを書くこともできます。

関連する問題

 関連する問題