質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

Q&A

解決済

2回答

311閲覧

ジェネレータによって返される値について

newyee

総合スコア213

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

0グッド

0クリップ

投稿2019/03/18 15:24

編集2019/03/18 15:35

ジェネレータにつきまして、お聞きしたいことがあります。

php

1<?php 2function gen_one_to_three() { 3 for ($i = 1; $i <= 3; $i++) { 4 // yield を繰り返す間、$i の値が維持されることに注目しましょう 5 yield $i; 6 } 7} 8 9$generator = gen_one_to_three(); 10foreach ($generator as $value) { 11 echo "$value\n"; 12} 13?>

上記の「$generator = gen_one_to_three();」ここの部分についてなのですが、「$generator」は「gen_one_to_three();」が処理された結果が入っていると思うのですが、returnでしたら、返り値が返ると思うのですが、returnはしていない為、何が代入されているかが分からないです...
var_dumpしてみましたら「object(Generator)#1 (0) { }」このように表示されたのですが、これも良く分かりません...
上記の点につきまして、混乱してしまっている部分もあるため、どなたかご教示頂けましたら幸いです。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

マニュアルから抜粋したのなら、マニュアルを読めばよいです。
yieldがキモです。

余談
php においてジェネレータ関数を使用するのは非常に限定的です。
・巨大なファイルの読み込み
・外部サービスの使用

今必要でないのであれば、混乱するし理解に時間がかかるので後回しにしたほうが良いです。
困ったときには自然と必要になりますが、(php を使用する上では)困るまで忘れて良いです仕組みです。

追記
コレで分かれば飛ばさなくてもイイよw

php

1<?php 2function gen_one_to_three() { 3 echo '1回目の呼び出し'.PHP_EOL; 4 yield 1; 5 echo '2回目の呼び出し'.PHP_EOL; 6 yield 2; 7 echo '3回目の呼び出し'.PHP_EOL; 8 yield 3; 9} 10 11$generator = gen_one_to_three(); 12foreach ($generator as $value) { 13 echo 'gen_one_to_three()を呼び出し'.PHP_EOL; 14 echo "$value".PHP_EOL; 15}

投稿2019/03/19 01:48

編集2019/03/19 02:01
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

newyee

2019/03/19 01:55

ご回答ありがとうございます。 PHPを学習している際に、関数の章でジェネレータが出てきたのですが、理解しておかなければ、この先困るかなと思っていたのですが、そうでないのなら、ここの部分は飛ばして先へ学習を進めようかなと思います!
退会済みユーザー

退会済みユーザー

2019/03/19 02:02

一応、フォローのつもりの追記をしました。 ただ、今はやっぱりわからないと思います。
newyee

2019/03/19 03:56

ありがとうございます。 papinianusさんのご回答も併せて、yieldに関して、大分理解することができました。
guest

0

ベストアンサー

PHPのジェネレータ構文の内部実装が実際のところどうなのかは分かりませんが、generatorの概念は次のようなクラスが背後にあると考えるのが理解しやすいと思います。

php

1<?php 2class gen_one_to_three implements Iterator { 3 private $start; 4 private $limit; 5 private $cur; 6 7 public function __construct() { 8 $this->start = 1; 9 $this->limit = 3; 10 $this->cur = 1; 11 } 12 function rewind() 13 { 14 $this->cur = $this->start; 15 } 16 17 function current() 18 { 19 return $this->cur; 20 } 21 22 function key() 23 { 24 return ($this->cur) - 1; 25 } 26 27 function next() 28 { 29 if($this->cur > $this->limit) { return FALSE; } 30 return $this->cur++; 31 } 32 33 function valid() 34 { 35 return $this->key() >= 0 && $this->key() < $this->limit; 36 } 37} 38$generator = new gen_one_to_three(); 39foreach ($generator as $value) { 40 echo "$value\n"; 41}

投稿2019/03/19 01:20

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

newyee

2019/03/19 01:37

ご回答ありがとうございます。 ご回答いただきました部分で、まだ勉強不足な為、理解できていない部分も多々あるため、取り敢えずは勉強を進めてみまして、再度頂いたご回答見直させて頂ければと思っております。 自分としましては、どうも「yield」の部分が理解できていないのですが、「gen_one_to_three」関数が実行された時点で、「yield」が実行されていますが、何か、配列のような形で「$i」が格納されているのかとかそういったことはあるのでしょうか...?
papinianus

2019/03/19 01:52

> 「gen_one_to_three」関数が実行された時点で、「yield」が実行されていますが 質問文のコードで話させてください。 ``` function gen_one_to_three() { for ($i = 1; $i <= 3; $i++) { // yield を繰り返す間、$i の値が維持されることに注目しましょう yield $i; } } ``` のことを言っているなら(タイプA)、gen_one_to_threeもyieldも実行していません。宣言だけですから。 ``` $generator = gen_one_to_three(); ``` のことを言っているなら(タイプB)、gen_one_to_threeは実行されたと言えますが、yieldは実行していません。 タイプBにおいて、`gen_one_to_three()`という(ジェネレータ形式の)関数を実行することは、「このあといつyieldをされても大丈夫になるための準備をした」にすぎません。 (もしご存知なら、関数を返す関数に似ています) yieldが実行されるのは、ジェネレータにforeachが「値を取り出せ!」という(人間が意識しない、裏側の)命令を出したときです。 > 何か、配列のような形で「$i」が格納されているのかとかそういったことはあるのでしょうか...? 答えとしては、そういったことはあるかもしれないし、ないかもしれない、です。 <この質問はgeneratorの本質から外れています。↓は無視したほうがいいくらいです> 配列だとしたら、[1,2,3]ですよね?$iは1または2または3です。かたち(型<カタ>)がちがいます。 質問のパターンであれば、内部的な実装で、[1,2,3]を配列で持つことは可能ですが、例えば、質問のコードでyieldのところで、mtrandなどを使ったり、 `while(true) yield $i++;`とした(無限に続く)ものは配列にはできません。 なので、配列っぽい動作、配列っぽい実装を想定して、そのとおりになるかどうかは局面による、としか言えません。 --- 回答の後出しになりますが、generatorはある種(ある種とは、foreachにかけられる、種類と理解してください)のクラスを簡単に作るための便利構文です。
newyee

2019/03/19 02:36

大変ご丁寧に教えてくださり、ありがとうございます。 うまく、お伝えできずにすみませんでした。自分の理解できない部分は、「タイプB」の部分でした。 「$generator = gen_one_to_three();」ここの部分におきましては、yieldは実行されていなかったんですね。すみません。一点だけ、分からない部分があるのですが「$generator = gen_one_to_three()」ここの部分の、$generatorには何が格納されているのでしょうか...? foreach内で、foreach ($generator as $value)このようにし、一つずつ値を取り出すよう命令が可能であれば、foreach (gen_one_to_three() as $value)このようなことも可能なのではないのかなと、もしくは記述的に不可能であっても内部的にはこのようなことが行われているのではないかなと思うのですが、いかがでしょうか...?
papinianus

2019/03/19 02:48

> $generatorには何が格納されているのでしょうか...? foreachできるようになったオブジェクトです。gen_one_to_threeの定義にある内部の処理をもった、インスタンスです。 -- この説明が適切か悩ましいのですが、$generator2 = gen_one_to_three();とすることができる、またこれは$generatorとは独立に動く、ことは理解できますでしょうか? <?php function gen_one_to_three() { for ($i = 1; $i <= 3; $i++) { // yield を繰り返す間、$i の値が維持されることに注目しましょう yield $i; } } $generator = gen_one_to_three(); $generator2 = gen_one_to_three(); foreach($generator as $value) { if($value == 2) break; echo "$value\n"; } // 再実行不可のエラーが出る /* foreach($generator as $value) { if($value == 2) break; echo "$value\n"; } */ // こっちは動く foreach($generator2 as $value) { echo "$value\n"; } ``` $generatorには、最初に書いたロジックをもった、しかし内部状態はまっさらな、インスタンスが入っています > foreach (gen_one_to_three() as $value)このようなことも可能 可能ですね。個人的にこういう感じでジェネレータ関数をforeachにつっこむことは良くやります。 ただ、こう書いたところで、関数を評価すると、foreach(object(generator) as $value)になって、 foreachとかasの作用で`->next()`が呼ばれ、そのとき`yield`の部分が実行されることにはかわりないです。
newyee

2019/03/19 03:26

ご返信ありがとうございます。 >またこれは$generatorとは独立に動く、ことは理解できますでしょうか? すみません。勉強不足でまだ、その辺りに関しましても理解があやふやな部分があるのですが、クラスを、newしてインスタンス化した場合は、別インスタンスが作られる、というのは知っているのですが、関数を複数の変数に代入した場合も別物として扱われる=独立したインスタンスとして扱うことができるということでしょうか...? 何度もお聞きして申し訳ないです...
papinianus

2019/03/19 03:41

var_dumpで確認した結果をはりつけていらっしゃるじゃないですか? > object(Generator) ですよね? つまり、generator形式の関数は、関数といいつつ、newしたときのようにインスタンスができます。(カッコの中に書いてあるとおり)Generatorクラスのインスタンスです。 なので、newじゃないのにnewしたみたいな、newじゃないのにインスタンスが返ってくるのが便利なところで、そうじゃなきゃ私の回答のようにクラスを作り込まないといけないのです。 > 何度もお聞きして申し訳ないです... 分かったフリをしない、その姿勢は素晴しいと思います。謝ることでは全然ないです。テトラちゃんです。
newyee

2019/03/19 03:49

ありがとうございます。 ご説明くださったおかげで、引っかかっていた部分が紐解けました。ご丁寧な説明で、ご質問させて頂いたことだけでなく、Generatorに関する知識が深まりました。何度もご親切に、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問