実際、ほとんどの場合は可能ですが、それでも非常に面倒な点もありますので、ゆっくりお話しましょう。
多くの言語は、配列を操作するための非常にエレガントで美しいメソッドを提供しています。次の例では、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 コードは実際にはラムダ分析を使用しており、実際のクロージャではありません。これは現在注目している点ではありません。 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); } function map($func) { $res = new self(); ($this as $k => $v) { $res[ $k ] = $func($k, $v); } return $res; } 関数 filter($func) { $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) マップ (_ * 2)。結局のところ、これらは本質的には単なる文法であり、同じ問題を異なるアプローチで解決します。プログラミング言語はそれぞれアプリケーションの特性が異なるため、どちらが優れていてどちらが劣っているかを比較することは当然できません。
最後に、この記事のコード例を紹介します (もちろん、これだけではありません)。
信頼性の低いブロガーの経験
正直に言うと、提案されている新しいクロージャやその他の機能については PHP5.0 以前から知っていましたが、PHP5.3 を見てからは気づきませんでした。クロージャと Lambda 関数を使用しても、元の心理学的期待とはまだ多少異なります。
馴染みのある JavaScript と比較しても、PHP のクロージャは、「他の言語にもクロージャがあるから、私もクロージャを持たなければならない」という考え方の産物であるように私には思えます。
しかし、上で述べたように、JavaScript などの他の動的言語と比較すると、PHP は独自のアプリケーションと実装の哲学により他の開発言語とは異なります。
そのため、特定の機能の呼び出し方法や実装方法が異なるため、同様の機能を持つ他の言語に慣れている人にとっては、必然的に違和感を覚えることになります。
PHP5.3 はリリースされてまだ半年も経っていませんが、既にクロージャなどの機能を備えている JavaScript や他の動的言語と比較すると、当然のことながら非常に未熟です。
同時に、大多数の開発者は、クロージャを含む PHP5.3 によって提供される新機能に対してまだ様子見の姿勢を保っています。 PHP のクロージャ機能はまだ研究室に存在しており、実際の開発に適用するには、言語機能のブレークスルーだけでなく、効率やセキュリティなどの観点からのテストも必要です。
しかし、原著者が言ったように、PHP のバージョンが進むにつれて、PHP クロージャ アプリケーションはますます頻繁になると思います。 PHP4 から PHP5 への変換と同様に、言語の新機能に適応することは、実際には苦しみながらも楽しいプロセスです。