ホームページ  >  記事  >  バックエンド開発  >  PHP クロージャー機能の実際的な応用の説明

PHP クロージャー機能の実際的な応用の説明

伊谢尔伦
伊谢尔伦オリジナル
2017-07-01 13:12:531736ブラウズ

PHP の新しいバージョンには多くの新機能が追加されており、最も目を引く機能の 1 つはクロージャのサポートです。では、将来的には、Ruby、Javascript、その他の「ハイテク言語」を書いている人たちのように、非常にクールなコードを書くことができるのでしょうか?

実際、ほとんどの場合は可能ですが、それでも非常に不安な点もありますので、ゆっくりお話しましょう。
多くの 言語 は、配列を操作するための非常にエレガントで美しいメソッドを提供します。次の例では、PHP5.3 などの言語で提供されているクロージャー関数を使用して、反復可能な配列を「客観的に」操作する方法を示します。
翻訳注釈: オリジナルの作者は比較的無知で、Groovy 言語と Scala 言語を理解していないため、ここに Javascript 実装を追加します。
始める前に説明させてください。この例は要点を説明するためのものであり、パフォーマンスなどの他の要素は考慮されていません。

「買い物をする」

次の配列を使用した簡単な例から始めます:
$nums = array(10, 20, 30, 40); 配列内で 15 より大きい項目を見つける必要があります。 。次に、クロージャを考慮せずに、次のように記述します:
$res = array();foreach ($nums as $n) { if ($n > 15) { $res[] = $n;言語自体には クロージャ サポート があるため、次のように記述することもできます (Groovy 言語)
def res = nums.findAll { it > 15 } または Scala 言語を使用します
val res = nums filter (_ > 15 )注: Javascript 1.6 の場合、次のようになります
var res = nums.filter(function(c){return c > 15}); ループ操作が抽象化されているため、Groovy と Scala (およびJavascript) 1行で済むのでとても綺麗です。
もちろんPHP5.3のクロージャを使えばそれも可能です
$res = array_filter($nums, function($v) { return $v > 15; });PHPはScalaよりも使います文字数は増えていますが、前の例よりも短くて読みやすくなっています。

ところで、上記の PHP コードは実際には Lambda 分析を使用しており、実際のクロージャではありません。これは現在注目している点ではありません。 PHP クロージャと Lambda 解析の詳細については、ここを参照してください。
ここまではかなりうまくできているようですので、問題の難易度を上げてみましょう。15 より大きい項目をすべて見つけて、2 を掛けて、スコープ内の変数の値を加算してから返します。

Groovy 実装:
def x = 1def res = nums .findAll { it > 15 } .collect { it * 2 + x }Scala 実装:
val x = 1val res = nums filter (_ > 15) _ * 2 + x) 翻訳アノテーション、JavaScript 実装:
var i = 1;var res = nums.filter(function(c){return c > 15}).map(function(c){return c * 2 + i}); および PHP:
$x = 1;$res = array_map( function($v) use ($x) { return $v * 2 + $x; }, array_filter( $nums, function ($ v) { return $v > 15 })); コードサイズの点で、PHP は他の言語とは異なるようです。コードの文字通りの美しさはさておき、上記の PHP コードにはさらに問題があります。
たとえば、比較に値の代わりに配列キーを使用する必要がある場合はどうすればよいでしょうか?はい、上記のコードは実行できません。また、構文的に言えば、上記のコードは非常に読みにくいです。

自然に立ち返って、問題を解決するにはやはり昔ながらの考え方に戻る必要があります:
$x = 1;$res = array();foreach ($nums as $n) { if ($n > 15) { $res [] = $n * 2 + $x; ふぅ、これでまた明らかですね。しかしこのとき、「なぜわざわざいじる必要があるの?これはただの配列演算ではないの?」と再び混乱するかもしれません。
はい、最高のものはまだ来ません。現時点では、自傷行為の傾向があるように見えるこの「退屈な問題」を解決するために、PHP の 高度な機能 を活用する時期が来ています。

ArrayObject - 配列のカプセル化
PHP には SPL と呼ばれる標準ライブラリがあり、これには ArrayObject と呼ばれるクラスが含まれており、「クラスを配列のように操作する」機能を提供できます。たとえば、
$res = new ArrayObject(array (10, 20, 30, 40));foreach ($res as $v) { echo "$vn";}ArrayObject は組み込みクラスであるため、他のクラス操作と同様にカプセル化できます。

Arr - シュガー コーティング

ArrayObject とクロージャの機能ができたので、それをカプセル化してみましょう:
class Arr extends ArrayObject{ static function make($array) { return new self($ array) ; } 関数マップ($func) { $res = new self(); ($this as $k => $v) { $res[$k] = $func($k, $v); $res; } 関数 filter($func) { $res = new self(); ($this as $k => $v) { if ($func($k, $v)) { $res [$ k] = $v; } } return $res }}準備は完了です。以下の書き換えられた PHP コードは上記の問題を解決でき、構文的には「ほぼ」似ています:

$res = Arr::make($nums) ->filter(function($k, $v) { return $v > 15; }) ->map(function($k, $v) { return $ v * 2; });上記のコードは従来の方法とどう違うのでしょうか?まず、再帰的呼び出しや連鎖呼び出しが可能であるため、より類似した操作を追加できます。

同時に、配列のキーと値は、コールバックの 2 つのパラメーターを通じてそれぞれ操作できます - $k はキーに対応し、$v は値に対応します。これにより、従来の PHP 関数 array_filter では不可能であった、クロージャでキー値を使用できるようになります。
もう 1 つの追加の利点は、より一貫性のある API 呼び出しです。従来の PHP 関数操作を使用すると、その最初のパラメータはクロージャ、配列、または複数の配列になる可能性があります... とにかく、誰にもわかりません。
これは Arr クラスの完全なソース コードです。これには他の便利な関数 (reduce や walk と同様) も含まれています。実際、それらの実装はコードと似ています。

ゲーム

この質問に答えるのは実際には難しいです。コードのコンテキストやプログラマー自身など、多くの要因に依存します。実際、PHP のクロージャ実装を初めて見たとき、匿名内部クラスを使用してクロージャを実装し始めた、はるか昔の Java の時代に戻ったような気がしました。もちろん、これを実行することもできますが、それは不必要に思えます。 PHP クロージャーには何の問題もありませんが、その実装と構文が私を混乱させます。
クロージャ機能を備えた他の言語では、クロージャを非常に便利に呼び出すことができ、エレガントな構文を備えています。上の例では、Scala の従来のループを使用することもできますが、このように記述しますか?一方で、上記の問題は PHP クロージャでも実現できるという人もいますが、一般的にはこのように書くのでしょうか?
PHP クロージャーは、状況によっては (実行の遅延やリソース呼び出しなど) 非常に強力であることは確かですが、従来の反復操作や配列操作に直面すると少し困難です。何があっても落胆しないでください。最も重要なことは、基本に立ち返り、互換性のあるクリーンなコードと API を作成することです。

結論

後から追加されたすべての構文機能 (当時の Java のジェネリック機能を覚えていますか? そしてその前の PHP OOP 機能) と同様に、それらはすべて実行されて最終的に安定するまでに時間がかかります。今後、PHP5.3、さらには PHP6 の人気が高まるにつれ、近い将来、より多くのテクニックや機能が賢明なプログラマーによって徐々に発見されるようになると思います。
元の記事の冒頭のタイトルに戻って比較してください
$res = Arr::make($nums) ->filter(function($k, $v) { return $v > 15; }) ->map( function($k, $v) { return $v * 2; }); と
val res = nums filter (_ > 15) map (_ * 2) の違い。結局のところ、これらは本質的には単なる構文であり、同じ問題を異なるアプローチで解決します。プログラミング言語はそれぞれアプリケーションの特性が異なるため、どちらが優れていてどちらが劣っているかを比較することは当然できません。
最後に、この記事のコード例を紹介します (もちろん、これだけではありません)。


以上がPHP クロージャー機能の実際的な応用の説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。