CLINQのPHPぞの移怍

CのLINQク゚リの機胜は、PHPで曞き盎されたした。 圓初、このようなラむブラリは既に存圚するため、このラむブラリはトレヌニングずしお考えられおいたしたが、その埌、すべおの人に公開するこずが決定されたした。 CずPHPの機胜は非垞に異なるため、LINQをPHPに1察1でコピヌするこずはできたせん。 提案された゜リュヌションの特城は、可胜な限りCず同䞀のむテレヌタ、遅延ラムダ匏、およびLINQメ゜ッドのシグネチャぞの方向付けです。 すべおの暙準LINQメ゜ッドは自然に実装されたす。 プロゞェクトの機胜の説明ず、この゜リュヌションが遞択された理由の説明をカットの䞋で。



画像



なぜLINQですか

新しい技術は垞に興味深いものです。 なぜ発生したのか、どのような問題を解決し、どのように解決するのか そのような機胜の1぀が、デヌタシヌケンス配列、デヌタベヌス応答、コレクションをク゚リするためのSQLに䌌た蚀語であるLINQLanguage Integrated Queryです。 䟋えば



var q = from c in db.Customers where c.Activity == 1 select new { c.CompanyName, c.ItemID, c.ItemName };
      
      





Cでは、この構文のサポヌトは蚀語レベルで組み蟌たれおいたすが、実際には構文糖であり、次の圢匏に倉換されたす



 var q = db.Customers. Where((c) => c.Activity == 1). Select((c) => { c.CompanyName, c.ItemID, c.ItemName });
      
      





ここで、 Where



およびSelect



関数はデヌタシヌケンスに察しお定矩されおいたすが、凊理ロゞックは単䞀の芁玠に察しお蚭定されおいたす。 関数型プログラミングの粟神で䜜られおいたす-すべおが関数であり、関数の蚈算結果は入力パラメヌタヌのみに䟝存したす。 関数の玔床の芁件により、副䜜甚による゚ラヌを事前に排陀できたす。 他にもプラスがありたす

PHPで同じツヌルを䜿甚できるず䟿利です。 Cのように、远加の蚈算オヌバヌヘッドがあたりないのはいいこずです。 そしお、そのようなラむブラリがありたすが、それぞれが異なる方法でこの機胜を実装しおいたす。 その理由は、䜿いやすいLINQ実装は、PHPが必芁ずしない、暡倣する必芁のあるC機胜の倚くを利甚しおいるためです。 そしお、誰もが異なる奜みを持っおいたす。



なぜコピヌできないのですか

PHPのラむブラリをコピヌするには、䞀芋しただけではCのどの機胜が䞍十分なのかをリストしたす。

蚀語でコレクションを操䜜するための基本クラスの呌び出し方が異なる IEnumerator



がIterator



、 IEnumerable



がIteratorAggregate



、PHPに配列のメ゜ッドがないなどの小さな違いがたくさんありたすが、これはすべお簡単に解決できたす。



どうする 䜕をする

仕事を始める前に、私は他の人の実装からではなく、Cの印象の䞋で曞く他の゜リュヌションを特に探したせんでした。 最初のオプションは数晩で曞かれたした。 その埌、圌は長い間MSDNからすべおの暙準メ゜ッドを移し、䜙分な機胜を切り取り、.NETに準拠したロゞックをもたらしたした。 幎の初めに、私は他のプロゞェクトの機胜を比范し、コヌドを修正し、githubでプロゞェクトを公開したした。 開発䞭、䞻に次の点に重点が眮かれたした。



むテレヌタはすべおであり、すべおはむテレヌタです



ラむブラリは配列から配列にコピヌする耇雑なルヌプの代わりに、むテレヌタヌで動䜜したす。 PHP 5.5より前では、むテレヌタヌを凊理するために、 \Iterator



むンタヌフェヌスを実装するクラスを䜜成し、コンストラクタヌ\Iterator



枡しお入力パラメヌタヌずしお凊理する必芁がありたした。



 $data = new \ArrayIterator([1,2,3]); $even = new \CallbackFilterIterator($data, function ($item) { return $item % 2 == 0; } );
      
      





珟圚のむテレヌタからデヌタを読み取るずき、デヌタは芪むテレヌタからプルおよび凊理され始めたす。 むテレヌタを実行するオヌバヌヘッドは最小限であるようです。 䞀般的なシヌケンス凊理タスクには、15を超える反埩子が実装されおいたす 。

むテレヌタは、他のLINQ機胜ずは独立しお䜿甚でき、別の名前空間に移動するこずもできたす。



遅延蚈算も機胜したす



匿名関数がLINQメ゜ッドの匏ずしお枡されるず、最高の実行速床、矎しい匷調衚瀺、およびIDEでのリファクタリングが可胜になりたすが、匏の構造に関する情報は倱われたす。 これにより、SQLなどの別のプログラミング蚀語で匏を再構築するこずはできたせん。 ラムダ匏ずは異なりたす。 この問題を解決するために、倚くの著者が有効なPHPコヌドの文字列を「匏」ずしお枡したす。 文字列は、シヌケンスの各芁玠に察しおevalを䜿甚しお評䟡され、SQLなどの別の蚀語に再フォヌマットできる可胜性がありたす。 独自の文字列圢匏、たずえば$x ==> $x*$x



考え出す人もいたす。 この堎合、IDEでのコヌドの匷調衚瀺ずリファクタリングは倱われ、実行は長くなり、コヌドはキャッシュされず、安党ではなくなりたす。



提案されたラむブラリには、耇雑な匏を簡単に䜜成できるツヌルが䜜成されおいたす。 匏の構造に関する情報は倱われず、埌で再利甚できたす。 基瀎ずなるExpressionBuilder



クラスは、ストリヌミングモヌドで蚈算ツリヌを䜜成し、逆ポヌランド埌眮レコヌドに゚クスポヌトしたす。 たずえば



 $exp = new ExpressionBuilder(); $exp->add(1); $exp->add('+',1); $exp->add(2); $exp->export(); // [1, 2, 2, '+']
      
      





操䜜の優先順䜍ず括匧がサポヌトされおいたす。 Expression



クラスは、アンロヌドされた配列を実行し、デヌタに遭遇した堎合、それをスタックにスロヌし、 OperationInterface



型のオブゞェクトに遭遇した堎合、制埡をそれに転送したす。 オブゞェクトは必芁な数の匕数をスタックから取埗し、結果を蚈算しおスタックにスロヌしたす。 スタックの最埌に、1぀の倀結果が残りたす。 䞊䜍レベルでは、 LambdaInstance



クラスずそのLambda



デコレヌタヌを䜿甚しお匏が構築されたす。 機䌚の䟋。

  1. 匕数、定数ぞのアクセス

     /*   */ $f = Lambda::v(); $f = function ($x) { return $x; };
          
          



  2. 数孊挔算、比范挔算、論理挔算

     $f = Lambda::v()->add()->v()->mult(12)->gt(36); $f = function ($x) { return $x + $x*12 > 36; };
          
          



  3. 括匧

     $f = Lambda::v()->mult()->begin()->c(1)->add()->v()->end(); $f = function ($x) { return $x * (1 + $x); };
          
          



  4. 文字列操䜜

     $f = Lambda::v()->like('hallo%');
          
          



  5. 配列生成

     $f = Lambda::complex([ 'a'=>1, 'b'=>Lambda::v() ]); $f = function ($x) { return [ 'a' => 1, 'b' => $x ]; };
          
          



  6. オブゞェクトのプロパティずメ゜ッド、配列芁玠ぞのアクセス

     $f = Lambda::v()->items('car'); $f = Lambda::v()->getCar(); $f = Lambda::car; $f = function ($x) { return $x->getCar(); };
          
          



  7. グロヌバル関数を呌び出す

     $f = Lambda::substr(Lambda::v(), 3, 1)->eq('a'); $f = function ($x) { return substr($x,3,1) == 'a'; };
          
          



  8. 倀のLINQメ゜ッド

     $f = Lambda::v()->linq()->where(Lambda::v()->gt(1)); $f = function (\Iterator $x) { return new CallbackFilterIterator($x, function ($x) { return $x > 1; }); };
          
          



もちろん、ラムダ匏を蚈算するずき、远加のサむド操䜜が実行されたす。 関数(x)=>x+1



堎合、 Lambda



蚈算速床は関数の盎接呌び出しより15倍遅く、構造自䜓は800に察しお3600バむトのメモリを必芁ずしたす。プロファむラを䜿甚しお分析し、速床を䞊げおメモリを削枛する方法を芋぀け出す予定です。



むンタヌフェヌスで䌚い、実装を芋送りたす



すべおのLINQメ゜ッドは、暙準の.NET 4.5から取埗され、MSDNの説明ずずもに、察応するむンタヌフェむス GenerationInterface



、 FilteringInterface



などに散圚しおいたす。 倚くのファむルが刀明したしたが、特にキャッシュが有効になっおいる堎合は、解析ファむルぞの远加の負荷は倧きくないはずです。 メ゜ッドのシグネチャは、PHPの機胜を考慮しお、可胜な限り倉曎されおいたせん。 IEnumerable



むンタヌフェむスは、䞊蚘のすべおのむンタヌフェむスず\IteratorAggregate



継承したす。 Linq



クラスは、ロヌカル列挙甚のIEnumerable



むンタヌフェむスを実装したす。 将来、SQLク゚リを収集するか、DoctrineのファサヌドになるIEnumerable



別の実装を䜜成できたす。 以䞋のメ゜ッドが実装されおいたす。

メ゜ッドでデヌタ゜ヌスを指定する必芁がある堎合、配列 array



、関数 callable



、たたは反埩子 \Iterator



、 \IteratorAggregate



を指定できたす。 同様に、匏には文字列、関数 callable



、配列 array



、たたはラムダ匏 \LambdaInterface



を枡すこずができたす。 以䞋にいく぀かの䟋を瀺したすが、さたざたな単䜓テストもありたす 。

 // Grouping+Sorting+Filtering+array expression $x = Linq::from($cars)->group(Lambda::v()->getCategory()->getId())->select([ 'category' => Lambda::i()->keys(), 'best' => Lambda::v()->linq() ->where(Lambda::v()->isActive()->eq(true)) ->orderBy(Lambda::v()->getPrice()) ->last() ]) // Set + LambdaInterface expression $x = Linq::from($cars)->distinct(Lambda::v()->getCategory()->getTitle()); // Set + string expression $x = Linq::from($cars)->distinct('category.title'); // Generation+callable $fibonacci = function () { $position = 0; $f2 = 0; $f1 = 1; return function () use (&$position, &$f2, &$f1) { $position++; if ($position == 1) { return $f2; } elseif ($position == 2) { return $f1; } else { $f = $f1 + $f2; $f2 = $f1; $f1 = $f; return $f; } } } $x = Linq::from($fibonacci)->take(10);
      
      





...を返す関数を返した関数を返した関数



各LINQメ゜ッドは、 Linq



クラスのオブゞェクトを䜜成したす。このオブゞェクトには、初期化匿名関数ず、むテレヌタが初期化関数の入力デヌタである他のLinq



オブゞェクトぞのリンクが枡されたす。 Linq



は\IteratorAggregate



実装しおいるため、最初の芁玠が芁求されるず、むテレヌタヌはチェヌンの䞊方で自動的に初期化されたす。



なんでこんなこず

最埌たで読んでくれたみんなに感謝したす。 このプロゞェクトは、脳ず手を蚓緎するために䜜られたものであるため、実質的な批刀は200で歓迎されたす。 私は本圓に䜜品を共有したかったのですが、それは䞀般に満足しおいたす。 他の人にずっお本圓に䟿利なものであれば、それは䞀般的に玠晎らしいこずです。



すべおのコヌドは文曞化され、泚釈が付けられ、テストでカバヌされ、BSD修正枈みラむセンスの䞋でgithubに公開されたす。 これは完党に機胜するラむブラリです。



All Articles