Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】Generator::send()メソッドの使い方

sendメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

sendメソッドは、ジェネレータ関数に外部から値を送信し、その実行を再開するメソッドです。

PHPのジェネレータは、yieldキーワードを使用して、実行を一時停止し、値を生成します。sendメソッドは、この一時停止中のジェネレータ関数へ、指定した値をyield式の戻り値として送り込むために使用されます。これにより、ジェネレータ関数は、yield式を通じて外部からのデータを受け取り、そのデータに基づいて処理を続けることが可能になります。

sendメソッドの引数$valueには、ジェネレータに送信したい任意の値を指定します。ジェネレータ内部では、yield式がこの$valueとして評価され、結果としてその値を受け取ることができます。

このメソッドの戻り値は、値を送信した後にジェネレータが次にyieldした値です。もしジェネレータがそれ以上yieldせず終了した場合、sendメソッドはnullを返します。

ジェネレータがまだyield式に到達していない初期状態やrewind()直後などにsendを呼び出した場合、送信された値は破棄されます。これは、ジェネレータが値を最初に受け取れるのは、少なくとも一度yield式に到達している必要があるためです。そのため、最初のyieldに値を送りたい場合は、next()で一度進めてからsend()を使うか、最初のsend()で値が破棄されることを理解した上で利用します。

構文(syntax)

1<?php
2
3function dataProcessorGenerator() {
4    $receivedData = yield; // ここで外部からデータを受け取る
5    yield 'Processed: ' . $receivedData; // 処理したデータを外部に返す
6}
7
8$generator = dataProcessorGenerator();
9
10// ジェネレータを開始し、最初のyieldまで実行(この時点ではデータは受け取らない)
11$generator->current();
12
13// sendメソッドでジェネレータに値を送信し、ジェネレータからの戻り値を受け取る
14$valueToSendToGenerator = 'Input Value';
15$valueReturnedFromGenerator = $generator->send($valueToSendToGenerator);
16
17?>

引数(parameters)

mixed $value

  • mixed $value: ジェネレーターに送信される値。yield式の結果として取得される。

戻り値(return)

mixed

Generator::send() メソッドは、ジェネレータに値を送信し、その値が処理された後に、ジェネレータが次に yield する値を返します。

サンプルコード

PHP Generator::send() で値を受け取り生成する

1<?php
2
3/**
4 * Generator::send() の使用例:値をジェネレータに送信し、次の値を生成する
5 */
6function numberGenerator(): Generator
7{
8    $i = 0;
9    while (true) {
10        $value = yield $i;
11
12        // send() で値が送信された場合、それを $i に加算する
13        if ($value !== null) {
14            $i += $value;
15        } else {
16            $i++;
17        }
18    }
19}
20
21$generator = numberGenerator();
22
23// 最初の値を生成
24echo "Initial value: " . $generator->current() . PHP_EOL; // Initial value: 0
25$generator->next();
26
27// 値を送信して次の値を生成
28echo "Value after send(5): " . $generator->send(5) . PHP_EOL; // Value after send(5): 6
29$generator->next();
30
31// 値を送信して次の値を生成
32echo "Value after send(10): " . $generator->send(10) . PHP_EOL; // Value after send(10): 17
33$generator->next();
34
35// 値を送信せずに次の値を生成
36echo "Value after next(): " . $generator->current() . PHP_EOL; // Value after next(): 18
37
38$generator->next();
39
40echo "Value after next(): " . $generator->current() . PHP_EOL; // Value after next(): 19

PHP 8 の Generator::send() メソッドは、ジェネレータ関数内で yield 式に値を送信し、ジェネレータの実行を再開して次の値を生成するために使用されます。Generator クラスに属するメソッドで、ジェネレータの内部状態を制御する重要な役割を担います。

引数 $value には、ジェネレータに送信する値を指定します。この値は、ジェネレータ関数内の yield 式の結果として変数に代入されます。

戻り値は、ジェネレータが次に yield した値です。ジェネレータが終了した場合や、return ステートメントに到達した場合は、NULL が返されます。

サンプルコードでは、numberGenerator() 関数がジェネレータとして定義されています。この関数は、while ループ内で yield $i を使用して値を生成し、send() で送信された値を $i に加算します。send() で値が送信されなかった場合は $i をインクリメントします。

$generator->send(5) は、ジェネレータに値 5 を送信し、ジェネレータの実行を再開します。ジェネレータ関数内では、$value5 が代入され、$i に加算されます。その結果、次の yield で生成される値は、加算後の $i の値となります。$generator->next() は、値を送信せずに次の値を生成します。send()next() を組み合わせることで、ジェネレータの動作を柔軟に制御できます。

Generator::send()メソッドは、ジェネレータ関数に値を送り、次の値を生成する際に使用します。yield式の結果として、送られた値を受け取れます。send()を使うとジェネレータの状態を外部から変更できるため、処理の流れを制御するのに役立ちます。

注意点として、send()を最初に呼び出すことはできません。ジェネレータは最初にnext()メソッドなどで起動する必要があります。また、send()で値を送信しない場合は、yield式の戻り値はnullになります。サンプルコードでは、$value !== nullで値が送信されたかどうかをチェックしています。send()に渡す値の型には注意し、ジェネレータ関数内で適切に処理されるようにする必要があります。

PHP Generator::send() でSendGridメールを動的に作成する

1<?php
2
3use SendGrid\Mail\Mail;
4
5/**
6 * SendGrid を使用してメールを送信するサンプル.
7 * Generator::send() を使用して値をジェネレータに送信し、メール内容を動的に生成する。
8 *
9 * @param string $apiKey SendGrid API キー
10 * @param string $toEmail 送信先メールアドレス
11 * @param string $subject メール件名
12 */
13function sendEmailWithGenerator(string $apiKey, string $toEmail, string $subject): void
14{
15    // メール送信処理を生成するジェネレータ
16    $emailGenerator = function (string $toEmail, string $subject) {
17        $email = new Mail();
18        $email->setFrom("from@example.com", "Example Sender");
19        $email->addTo($toEmail, "Example Recipient");
20        $email->setSubject($subject);
21
22        // ジェネレータに値を送信して本文を生成
23        $body = yield; 
24        $email->addContent("text/plain", $body);
25
26        yield $email; // メールオブジェクトを返す
27    };
28
29
30    $generator = $emailGenerator($toEmail, $subject);
31
32    // ジェネレータを開始
33    $generator->rewind();
34
35    // Generator::send() でメール本文をジェネレータに送信
36    $generator->send("This is the dynamic email body sent using Generator::send().");
37
38    /** @var Mail $email */
39    $email = $generator->current();
40    
41    try {
42        $sendgrid = new SendGrid($apiKey);
43        $response = $sendgrid->send($email);
44        
45        // デバッグ用
46        //echo $response->statusCode() . "\n";
47        //print_r($response->headers());
48        //echo $response->body() . "\n";
49
50    } catch (Exception $e) {
51        echo 'Caught exception: '. $e->getMessage() ."\n";
52    }
53}
54
55// SendGrid APIキー、送信先メールアドレス、メール件名を指定して実行
56// sendEmailWithGenerator("YOUR_SENDGRID_API_KEY", "to@example.com", "Dynamic Email Subject");
57

このサンプルコードは、PHPのジェネレータ機能とSendGridライブラリを組み合わせて、動的にメールを生成・送信する方法を示しています。Generator::send()メソッドは、ジェネレータ関数に値を送信するために使用されます。

まず、sendEmailWithGenerator関数は、SendGrid APIキー、送信先メールアドレス、メール件名を引数として受け取ります。この関数内で、メール送信処理を生成するジェネレータ関数 $emailGenerator が定義されています。$emailGenerator は、yield キーワードを使って一時停止し、Generator::send() で送信された値(この場合はメール本文)を受け取ります。そして、受け取った値をメール本文として設定し、最終的にメールオブジェクトを yield します。

次に、$emailGenerator からジェネレータオブジェクトが生成され、rewind() メソッドでジェネレータが開始されます。Generator::send("This is the dynamic email body...") の部分で、メール本文が $emailGenerator に送信されます。送信された値は $body = yield; で受け取られ、メールオブジェクトに設定されます。

ジェネレータからメールオブジェクトを受け取った後、SendGridライブラリを使用して実際にメールを送信します。Generator::send() は、ジェネレータに値を渡すだけでなく、ジェネレータが次に yield する値(この例ではメールオブジェクト)を返す役割も果たします。エラーが発生した場合は、例外がキャッチされ、エラーメッセージが表示されます。最後に、コメントアウトされている sendEmailWithGenerator("YOUR_SENDGRID_API_KEY", "to@example.com", "Dynamic Email Subject"); の部分を、実際のAPIキーとメールアドレスに置き換えることで、メールを送信できます。

Generator::send()は、ジェネレータ関数内でyieldされた箇所に値を渡すメソッドです。このサンプルでは、メール本文を動的に生成するために使用されています。$generator->rewind()でジェネレータを初期状態に戻す必要があります。yield式がない状態でsend()を呼ぶとエラーになるため注意してください。SendGrid APIキーは必ずご自身のものを設定し、送信先メールアドレスも有効なものを指定してください。また、コメントアウトされているデバッグ用のコードは、必要に応じて有効活用してください。本番環境では、APIキーをソースコードに直接記述せず、環境変数などを用いて安全に管理することを推奨します。

PHP Generator::send でメール送信を制御する

1<?php
2
3/**
4 * Generator::send() メソッドのデモンストレーションとして、
5 * 擬似的なメール送信タスクのステップを協調的に制御するジェネレータです。
6 *
7 * ジェネレータは各ステップで処理を中断 (yield) し、
8 * 外部から Generator::send() を介して次の処理に必要な情報を受け取ります。
9 * これにより、非同期処理や外部サービスとのやり取りをシミュレートし、
10 * Generator::send() の役割を具体的に示します。
11 *
12 * @return Generator
13 */
14function simulateEmailSenderTask(): Generator
15{
16    echo "--- 擬似メール送信タスク開始 ---\n";
17
18    // ステップ1: SMTPサーバーへの接続をシミュレート
19    // yield は値を外部に返し、ここで処理を中断します。
20    // 外部から send() で値が送られるまで待機します。
21    echo "ジェネレータ内部: SMTPサーバーに接続を試みています...\n";
22    $connectionStatus = yield 'waiting_for_connection_status'; // 外部からの接続結果を待つ
23
24    echo "ジェネレータ内部: 外部から接続ステータスを受け取りました: " . $connectionStatus . "\n";
25    if ($connectionStatus !== 'connected') {
26        echo "ジェネレータ内部: エラー: SMTP接続に失敗しました。\n";
27        return false; // タスク失敗
28    }
29    echo "ジェネレータ内部: SMTPサーバーに接続成功しました。\n";
30
31    // ステップ2: 認証情報を送信し、認証をシミュレート
32    echo "ジェネレータ内部: 認証情報を送信中です...\n";
33    $authenticationResult = yield 'waiting_for_authentication_result'; // 外部からの認証結果を待つ
34
35    echo "ジェネレータ内部: 外部から認証結果を受け取りました: " . $authenticationResult . "\n";
36    if ($authenticationResult !== 'authenticated') {
37        echo "ジェネレータ内部: エラー: 認証に失敗しました。\n";
38        return false; // タスク失敗
39    }
40    echo "ジェネレータ内部: 認証に成功しました。\n";
41
42    // ステップ3: メール本文と宛先を送信する準備
43    echo "ジェネレータ内部: メールデータを準備中です...\n";
44    $mailData = yield 'waiting_for_mail_data'; // 外部からのメールデータを待つ
45
46    echo "ジェネレータ内部: 外部からメールデータを受け取りました。\n";
47    if (!isset($mailData['to']) || !isset($mailData['subject']) || !isset($mailData['body'])) {
48        echo "ジェネレータ内部: エラー: 不完全なメールデータが渡されました。\n";
49        return false; // タスク失敗
50    }
51    echo "ジェネレータ内部: メールを '{$mailData['to']}' (件名: '{$mailData['subject']}') に送信中です...\n";
52
53    // ステップ4: 最終的な送信結果を待機
54    echo "ジェネレータ内部: 外部サービスからの最終送信結果を待機中です...\n";
55    $finalSendResult = yield 'waiting_for_final_send_result'; // 外部からの送信結果を待つ
56
57    echo "ジェネレータ内部: 外部から最終送信結果を受け取りました: " . $finalSendResult . "\n";
58    if ($finalSendResult === 'success') {
59        echo "ジェネレータ内部: メール送信が成功しました!\n";
60        return true; // タスク成功
61    } else {
62        echo "ジェネレータ内部: エラー: メール送信に失敗しました。\n";
63        return false; // タスク失敗
64    }
65}
66
67// ジェネレータインスタンスを作成し、タスクを開始します。
68$emailSender = simulateEmailSenderTask();
69
70// ジェネレータを最初の yield まで実行し、その yield された値を取得します。
71// ここでタスクは中断され、外部からの情報待ちになります。
72echo "外部コントローラー: ジェネレータが中断しました。要求: " . $emailSender->current() . "\n";
73
74// Generator::send() を使ってジェネレータに値を送り込み、次の yield まで実行させます。
75// ここではSMTP接続が成功したと仮定して 'connected' を送ります。
76// send() の戻り値は、次に yield された値です。
77echo "外部コントローラー: ジェネレータに 'connected' を送ります。\n";
78echo "外部コントローラー: ジェネレータが中断しました。要求: " . $emailSender->send('connected') . "\n";
79
80// 認証が成功したと仮定して 'authenticated' を送ります。
81echo "外部コントローラー: ジェネレータに 'authenticated' を送ります。\n";
82echo "外部コントローラー: ジェネレータが中断しました。要求: " . $emailSender->send('authenticated') . "\n";
83
84// 送信するメールデータを連想配列としてジェネレータに送ります。
85$mailDetails = [
86    'to'      => 'beginner@example.com',
87    'subject' => 'PHP Generator::send デモンストレーション',
88    'body'    => 'このメールは、PHPのGenerator::sendメソッドの動作を示すために送信されました。'
89];
90echo "外部コントローラー: ジェネレータにメールデータを送ります。\n";
91echo "外部コントローラー: ジェネレータが中断しました。要求: " . $emailSender->send($mailDetails) . "\n";
92
93// 最終的な送信結果をジェネレータに送ります。
94// ここでジェネレータは return ステートメントに到達し、完了します。
95// 完了後の send() の戻り値は通常 null です(次に yield される値がないため)。
96echo "外部コントローラー: ジェネレータに 'success' を送ります。\n";
97$emailSender->send('success');
98
99// ジェネレータが有効 (まだ yield 可能) かどうかを確認します。
100if (!$emailSender->valid()) {
101    echo "--- 擬似メール送信タスク完了 ---\n";
102    // ジェネレータの return で返された最終結果を取得します (PHP 7.0 以降)。
103    echo "最終タスク結果: " . ($emailSender->getReturn() ? "成功" : "失敗") . "\n";
104}
105
106?>

PHPのGenerator::sendメソッドは、ジェネレータという特殊な関数と組み合わせて使われます。ジェネレータは、処理の途中で一時停止し(yieldキーワード)、外部に値を返しながら、必要に応じて中断した場所から処理を再開できる機能です。

sendメソッドは、この一時停止中のジェネレータに対して、外部から値を送り込み、処理を再開させる役割を持ちます。引数 $value には、ジェネレータ内部の yield 式が受け取る値を指定します。これにより、ジェネレータは外部から送られた情報に基づいて次の処理を進めることができます。sendメソッドの戻り値は、ジェネレータが次に yield した値です。ジェネレータが処理を完了し、もう yield するものがない場合は null を返します。

このサンプルコードでは、擬似的なメール送信タスクを通じて send メソッドの動作を示しています。ジェネレータ内部の simulateEmailSenderTask 関数は、SMTP接続、認証、メールデータ送信、最終送信結果の取得という各ステップで yield を使用して処理を中断し、「接続ステータス待ち」や「認証結果待ち」といったメッセージを外部に伝えます。

外部のコントローラー(サンプルコードの下半分)は、$emailSender->current() でジェネレータの要求を確認し、$emailSender->send() を使って「connected」や「authenticated」、実際のメールデータなどを送り込みます。これにより、まるで外部サービスと対話するように、ジェネレータのメール送信プロセスを段階的に制御しています。最終的に、ジェネレータは全てのステップを完了し、getReturn() メソッドで最終的な成功・失敗の結果を取得しています。

Generator::send()は、yieldで一時停止したジェネレータに外部からデータを渡すための機能です。yieldはジェネレータから外部へ値を渡し、send()はその反対に外部からジェネレータへ値を送ることで、双方向のやり取りを実現します。このサンプルコードは、SMTP通信のような時間のかかるステップを協調的に制御する例として参考にしてください。これにより、擬似的な非同期処理に近い制御が可能になります。ジェネレータ内で値を受け取った際は、常にその値が期待通りか検証し、エラー時には適切にタスクを終了するロジックを記述することが重要です。ジェネレータが完了した後にsend()を呼び出しても、それ以上処理は進まず、通常はnullが返されますので、valid()で完了を確認し、getReturn()で最終結果を取得するようにしてください。

PHPジェネレータ双方向通信で値を受け渡す

1<?php
2
3/**
4 * 双方向通信が可能なジェネレータの例。
5 * yield式は値を生成するだけでなく、Generator::send() メソッドで送られた値を受け取ることもできます。
6 *
7 * @return Generator
8 */
9function bidirectionalGenerator(): Generator
10{
11    echo "ジェネレータ: 開始します。" . PHP_EOL;
12
13    // 最初の yield: 'Hello!' を生成し、外部から値が送られるまで待機する
14    // send() で送られた値は $receivedValue に代入される
15    $receivedValue = yield 'Hello from generator!';
16    echo "ジェネレータ: 外部から '" . $receivedValue . "' を受け取りました。" . PHP_EOL;
17
18    // 2番目の yield: 'How are you?' を生成し、外部から値が送られるまで待機する
19    $receivedValue = yield 'How are you?';
20    echo "ジェネレータ: 外部から再び '" . $receivedValue . "' を受け取りました。" . PHP_EOL;
21
22    echo "ジェネレータ: 終了します。" . PHP_EOL;
23    return 'Generator finished its work.'; // PHP 7以降でジェネレータの戻り値を指定可能
24}
25
26// ジェネレータを作成
27$generator = bidirectionalGenerator();
28
29// ジェネレータを開始し、最初の yield から値を受け取る (この時点でジェネレータは最初の yield で一時停止)
30echo "メイン: ジェネレータから '" . $generator->current() . "' を受け取りました。" . PHP_EOL;
31
32// Generator::send() を使用してジェネレータに値を送り込み、
33// 次の yield から値を受け取る (ジェネレータは次の yield で一時停止)
34// 'Nice to meet you!' がジェネレータ内部の $receivedValue に代入される
35echo "メイン: ジェネレータに 'Nice to meet you!' を送ります。" . PHP_EOL;
36echo "メイン: ジェネレータから '" . $generator->send('Nice to meet you!') . "' を受け取りました。" . PHP_EOL;
37
38// 再び Generator::send() を使用してジェネレータに値を送り込む
39// 'I am fine!' がジェネレータ内部の $receivedValue に代入される
40echo "メイン: ジェネレータに 'I am fine!' を送ります。" . PHP_EOL;
41$finalValue = $generator->send('I am fine!');
42
43// ジェネレータがこれ以上値を生成しないことを確認
44if (!$generator->valid()) {
45    echo "メイン: ジェネレータは終了しました。" . PHP_EOL;
46    // PHP 7以降でジェネレータの戻り値を取得
47    echo "メイン: ジェネレータの戻り値は '" . $generator->getReturn() . "' でした。" . PHP_EOL;
48}

PHPのGenerator::send()メソッドは、ジェネレータ関数に対して外部から任意の値を送り込み、同時にジェネレータが次に生成する値を受け取るための重要な機能です。このメソッドを利用することで、ジェネレータと呼び出し元のコードとの間で、値の「送信」と「受信」を同時に行う双方向通信が実現できます。

サンプルコードでは、bidirectionalGeneratorというジェネレータ関数を作成し、その動作を示しています。まず、$generator->current()を呼び出すことで、ジェネレータは最初のyield式で生成した「Hello from generator!」という値を外部に渡し、その時点で処理を一時停止します。

次に$generator->send('Nice to meet you!')が呼び出されると、引数として渡された'Nice to meet you!'が、ジェネレータ内部で直前のyield式の戻り値として$receivedValue変数に代入されます。同時にジェネレータは処理を再開し、次のyield式である「How are you?」を生成してsend()メソッドの戻り値として外部に返します。このように、send()の引数$valueはジェネレータに渡され、戻り値はジェネレータが次に生成する値となります。

この一連の動作により、ジェネレータは生成した値に対する外部からの応答を受け取り、それに基づいて次の処理を行うことが可能になります。ジェネレータが完了すると$generator->valid()falseとなり、$generator->getReturn()でジェネレータの最終的な戻り値を取得できます。

Generator::send() メソッドは、ジェネレータの実行を再開すると同時に、yield式へ値を渡す機能があります。ジェネレータ側ではyield式の左辺に、外部からsend()で送られた値が代入されます。初めてsend()を呼び出す際は、ジェネレータがまだ開始されていないためエラーとなる点に注意が必要です。必ず事前にcurrent()next()でジェネレータを開始してから使用してください。send()の戻り値は、ジェネレータが次にyieldした値です。また、ジェネレータの処理が完全に終了した後は、getReturn()メソッドで最終的な戻り値を取得できることも覚えておくと良いでしょう。

関連コンテンツ

関連IT用語