Jadual Kandungan
通过例子来了解它" >通过例子来了解它
怎样才能产生 Generator" >怎样才能产生 Generator
生成器的函数" >生成器的函数
Generator::current" >Generator::current
Generator::send" >Generator::send
Generator::next" >Generator::next
Generator::rewind" >Generator::rewind
Generator::throw" >Generator::throw
Generator::valid" >Generator::valid
Generator::key" >Generator::key
Generator::__wakeup" >Generator::__wakeup
Generator::getReturn" >Generator::getReturn
Rumah pembangunan bahagian belakang tutorial php PHP yield 协程 生成器用法的了解

PHP yield 协程 生成器用法的了解

Jul 02, 2020 pm 06:02 PM
php yield coroutine penjana

PHP yield 协程 生成器用法的了解

写在前面

这篇文章,要和大家探讨的是 PHP yield 在 生成器用法,不带 foreachfor, while 循环的那种。就讨论 yield 将一个函数变成为生成器的用法。

关于yield 特性,是在开发 PHP5 时被提上日程,PHP5.5 版本正式加入。

关于yield的使用,我看到大部分文章都停留在,使用yield如何在foreach中穿出数据,今天想给大家讲讲 生成器 所有语法。

相关学习推荐:PHP编程从入门到精通

官网讲解

生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。

看了下官网对他讲解:php.net 生成器语法  . 每个字都认识,但似乎还是体会到它讲的内涵。官网我们主要看两部分内容:

  1. yield 的语法。

  2. 代码例子。

先说语法, yield 的左边是一个赋值语句,右边可以是值(也可是表达式) 。而yield 会先执行右边的表达式,并把值$value送到生成器外面。当生成器收到值后,会执行yield左边的语句,赋值给$data.

<?phpfunction func(){
    $data = (yield [$express]);}
Salin selepas log masuk

语法就这样,估计大家还是有些懵,那就看看官网下面代码例子吧,我看里面例子参差不齐。

注意yield 外面包的这一层括号,如果是在php5.5,右侧$express的优先级是判断,可能会比左侧$data的赋值语句低的。所以在php5用yield,yield 右边是可运行表达式,左侧需要接受返回并赋值,那么这个括号是有必要的。在php7不会有这个问题。

不论是学 人类语言,计算机语言,都是模仿开始

对于一个用人类语言来描述,都不那么明晰时,所以那就通过例子告诉你它能做什么,不能做什么。

相关代码,我放到gitee了,希望你能复制到你本地运行下,亲自运行感受下,有助于了理解接下来的内容。

git clone gitee.com/xupaul/PHP-generator-yie...

先定义一个函数,在函数内 写个 yield 关键词,将这个函数调用赋值给一个变量。一个生成器就产生了。

代码 /php-yield-test/yieldFunctions.php 是生成器按照不同语法组合定义了多个生成器。

测试代码 /php-yield-test/whatIsGenerator.php,用来检查哪些函数能构成生成器,哪些不能。运行结果如下

test result

  1. 函数内必须有 yield 关键词,函数可以是全剧函数,或者类的方法。
  2. 哪怕 yield 肯定不会被执行,也会产生生成器。见:yield_func4
  3. 光秃秃 的 yield 关键词就行(不向外送出,不处理外面的输入)。见: yield_func2
  4. 函数内使用 生成器 并不能让自己也成为生成器,见:yield_func5
  5. eval函数中直接运行 yield 会报错, 见:yield_func11

是的,函数内有没有foreach,while,for 语句都不是关键,关键是 yield. 生成器的类型判断用 $gen instanceof Generator

Generator 对象是从 generators返回的.

Generator 对象不能通过 new 实例化.

  • Generator::current — 返回当前产生的值
  • Generator::key — 返回当前产生的键
  • Generator::next — 生成器继续执行
  • Generator::rewind — 重置迭代器
  • Generator::send — 向生成器中传入一个值
  • Generator::throw — 向生成器中抛入一个异常
  • Generator::valid — 检查迭代器是否被关闭
  • Generator::__wakeup — 序列化回调
  • Gengerator::getReturn - Get the return value of a generator

摘自 php.net generator

看着以上方法,是不想起了Iterator, 他们的确很像。同时注意,官网zh语言版本的文档没有索引方法getReturn,访问也是404。文档以en版为准,ch做参考。

以上就是生成器所有的方法,我们一个个来看。

测试方法代码 /php-yield-test/generatorMothod.php, 这里面对每个方法都有使用举例,运行结果如下。

run result 2

run result 3

好接下来对举例做个一一讲解。

  • 返回当前产生的值
<?phpfunction yield_func(){
    yield 12;
    return &#39;a&#39;;}$gen = yield_func();$re = $gen->current();echo &#39;current return : &#39; . $re;
Salin selepas log masuk

输出:

current return : 12
Salin selepas log masuk

看到 php-yield-test/generatorMothod.php 代码。

通过第一个代码事例,可得,对一个generator调用current方法,才算真正开始执行。执行到yield为止。如果不能命中yield,则执行到函数结束。

非generoator会立马执行并得到结果,而非一个生成器对象。

通过例子2,调用current一次,两次呢,第一次可以看到代码执行日志,第二次,只是把上一次的结果返回给我们而已,并不是让该生成器重新执行。

通过例子1,调用该函数还会获取到返回值,返回的内容就是 yield 表达式左边的内容。如果表达式无内容,则是NULL.

  • 向生成器yield点中传入一个值,并返回下一次current值。
<?phpfunction yield_func(){
    $data = yield 12;
    echo &#39;get yield data: &#39; . $data;
    return &#39;a&#39;;}$gen = yield_func();$re = $gen->current();$gen->send(32);
Salin selepas log masuk

输出:

get yield data: 32
Salin selepas log masuk

例子3,是一个current,send的常规调用。调用current代码运行yield等到用户send输入参数。接收到输入后,继续运行。current能够接收到yield弹出的值,send返回值为空。

例子4,直接调用send,相当于调用current,send。不过current的返回值,并不会通过send传给用户。

例子21中,可以看到直接调用send(1),会运行生成器,并向第一个yield处输入1,继续运行至下一个yield的返回值value。所以,$gen->send(2),和 $gen->current() 结果都是同一个值。

也就是说:跳过current,直接调用send,会丢失第一次yield的弹出值。

  • 跳过中断,并让生成器继续执行
<?phpfunction yield_func(){
    echo &#39;run to code line: &#39; . __LINE__ . PHP_EOL;
    yield;
    echo &#39;run to code line: &#39; . __LINE__ . PHP_EOL;
    return $result;}$gen = yield_func();$gen->current();echo &#39;current called&#39; . PHP_EOL;$gen->next();
Salin selepas log masuk

输出:

run to code line: 4current called
run to code line: 6
Salin selepas log masuk

例子5,这是一个较为常规的调用,调用current代码运行yield等到用户输入,这是调用next跳过,让代码继续运行。

例子6,直接调用next,相当于调用currentnext。而且通过最后打印$result, 我们发现怎么有点像在调用 $gen->send(NULL);

  • 重置迭代器
<?phpfunction yield_func(){
    echo &#39;run to code line: &#39; . __LINE__ . PHP_EOL;
    $result = yield 12;
    echo &#39;run to code line: &#39; . __LINE__ . PHP_EOL;}$gen = yield_func();echo &#39;call yield_func rewind &#39; . PHP_EOL;$gen->rewind();
Salin selepas log masuk

输出:

call yield_func rewind 
run to code line: 4
Salin selepas log masuk

例子7,8 中,发现调用该方法,会导致隐式调用current

例子9 中,发现在执行过一个yield代码段后,再次调用该方法,会导致报错(哪怕该 生成器已结束)。

  • 向生成器中抛入一个异常
<?phpfunction yield_func(){
    try {
        $re = yield &#39;exception&#39;;
    } catch (Exception $e) {
        echo &#39;catched exception msg: &#39; .$e->getMessage();
    }}$gen = yield_func();$gen->throw(new \Exception(&#39;new yield  exception&#39;));
Salin selepas log masuk

输出:

catched exception msg: new yield  exception
Salin selepas log masuk

通过以上简单的例子可得,throw 就是让yield这行代码产生异常,让外面的try catch 捕获我们生成的那个异常。

例子11中,构造生成器,并调用current方法,运行到yield处,再调用throw,就能捕获到异常。

例子12中,当调用send方法,跳过函数内yield代码时,再调用throw传入异常,就没法捕获了。

  • 检查迭代器是否被关闭
<?phpfunction yield_func(){
    yield 12;
    return &#39;a&#39;;}$gen = yield_func();$gen->send(1);$check = $gen->valid();echo &#39;the generator valid ? &#39; . intval($check);
Salin selepas log masuk

输出:

the generator valid ? 0
Salin selepas log masuk

例子12中,发现current被隐式调用。

例子13中,可得,当生成器运行到yield代码段时,用valid函数检查,都会返回true

所以,别问我是否已运行,问就是运行。该方法用来获取是否关闭状态,不是 是否运行状态!运行到底,运行到return就是 关闭状态。

  • 返回当前产生的键
<?phpfunction yield_func(){
    yield 1 => &#39;abc&#39;;}$gen = yield_func();echo &#39;value is :&#39; . $gen->current() . PHP_EOL;echo &#39;key is: &#39; . $gen->key() . PHP_EOL;
Salin selepas log masuk

输出:

value is :abc
key is: 1
Salin selepas log masuk

从以上例子中,可得yield可显示设置返回的key.

例子15 中,发现key的分发规律和PHP数组键值发放策略是差不多的,默认从0开始,未指定则是以上一个数字key+1作为当前的key.

例子16 中,我们又发现current被隐式调用。

  • Generator::__wakeup — 序列化回调
<?phpfunction yield_func(){
    yield 1 => &#39;abc&#39;;}$gen = yield_func();try {$ser = serialize($gen);} catch (\Exception $e) {
    print_r($e->getMessage());}
Salin selepas log masuk

输出:

Serialization of &#39;Generator&#39; is not allowed
Salin selepas log masuk

这是一个魔术方法,见 PHP 魔术方法,也就是说 生成器 不能被序列化成一个字符串。

例子17就不用说了,看下例子18,看样子序列化成功了。也就是说一个生成器做为一个方法可以被序列化,当函数变成生成器时,就不能被序列化了。

<?phpfunction yield_func(){
    yield 1 => &#39;abc&#39;;
    return 32;}$gen = yield_func();$gen->send(0);echo &#39;call yield_func return, and get: &#39; . $gen->getReturn();
Salin selepas log masuk

输出:

call yield_func return, and get: 32
Salin selepas log masuk

该函数就是获取生成器最后的返回值。如果没有return语句,或者没有执行到return语句,调用该函数得到的就是NULL。

例子19 可得,getReturn 能够获取到生成器最后的返回值。

例子19、20 可得,当生成器没有执行到return语句,或者没有执行到最后时,调用getReturn是会导致报错。

综上所述

到这里,我们就发现rewind,next__wakeup 这两个函数感觉没啥叼用呢,为啥还存在呢,因为Generator继承Iterator,自然就有了rewind, next方法,PHP 虽然支持方法覆盖,但子类的访问修饰符 不能缩紧,所以Generator只能重写这两个方法。 __wakeup 继承自 stdClass

状态转换

看图:

PHP yield 生命周期图

画了两个状态转换图,上面的要细致,繁复一点。下面的精简版,便于快速理解。

总结

以上就是关于 PHP 生成器的基础内容,希望你看了后对它有更进一步认识。下一讲,我们手把手一起来做一个任务调度器,实战一下。

有问题欢迎提问,谢谢大家!

没人比我更懂

Atas ialah kandungan terperinci PHP yield 协程 生成器用法的了解. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Akan R.E.P.O. Ada Crossplay?
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 membawa beberapa ciri baharu, peningkatan keselamatan dan peningkatan prestasi dengan jumlah penamatan dan penyingkiran ciri yang sihat. Panduan ini menerangkan cara memasang PHP 8.4 atau naik taraf kepada PHP 8.4 pada Ubuntu, Debian, atau terbitan mereka

Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Dec 20, 2024 am 11:31 AM

Kod Visual Studio, juga dikenali sebagai Kod VS, ialah editor kod sumber percuma — atau persekitaran pembangunan bersepadu (IDE) — tersedia untuk semua sistem pengendalian utama. Dengan koleksi sambungan yang besar untuk banyak bahasa pengaturcaraan, Kod VS boleh menjadi c

7 Fungsi PHP Saya Menyesal Saya Tidak Tahu Sebelum ini 7 Fungsi PHP Saya Menyesal Saya Tidak Tahu Sebelum ini Nov 13, 2024 am 09:42 AM

Jika anda seorang pembangun PHP yang berpengalaman, anda mungkin merasakan bahawa anda telah berada di sana dan telah melakukannya. Anda telah membangunkan sejumlah besar aplikasi, menyahpenyahpepijat berjuta-juta baris kod dan mengubah suai sekumpulan skrip untuk mencapai op

Bagaimana anda menghuraikan dan memproses HTML/XML dalam PHP? Bagaimana anda menghuraikan dan memproses HTML/XML dalam PHP? Feb 07, 2025 am 11:57 AM

Tutorial ini menunjukkan cara memproses dokumen XML dengan cekap menggunakan PHP. XML (bahasa markup extensible) adalah bahasa markup berasaskan teks yang serba boleh yang direka untuk pembacaan manusia dan parsing mesin. Ia biasanya digunakan untuk penyimpanan data

Jelaskan JSON Web Tokens (JWT) dan kes penggunaannya dalam PHP API. Jelaskan JSON Web Tokens (JWT) dan kes penggunaannya dalam PHP API. Apr 05, 2025 am 12:04 AM

JWT adalah standard terbuka berdasarkan JSON, yang digunakan untuk menghantar maklumat secara selamat antara pihak, terutamanya untuk pengesahan identiti dan pertukaran maklumat. 1. JWT terdiri daripada tiga bahagian: header, muatan dan tandatangan. 2. Prinsip kerja JWT termasuk tiga langkah: menjana JWT, mengesahkan JWT dan muatan parsing. 3. Apabila menggunakan JWT untuk pengesahan di PHP, JWT boleh dijana dan disahkan, dan peranan pengguna dan maklumat kebenaran boleh dimasukkan dalam penggunaan lanjutan. 4. Kesilapan umum termasuk kegagalan pengesahan tandatangan, tamat tempoh, dan muatan besar. Kemahiran penyahpepijatan termasuk menggunakan alat debugging dan pembalakan. 5. Pengoptimuman prestasi dan amalan terbaik termasuk menggunakan algoritma tandatangan yang sesuai, menetapkan tempoh kesahihan dengan munasabah,

Program PHP untuk mengira vokal dalam rentetan Program PHP untuk mengira vokal dalam rentetan Feb 07, 2025 pm 12:12 PM

Rentetan adalah urutan aksara, termasuk huruf, nombor, dan simbol. Tutorial ini akan mempelajari cara mengira bilangan vokal dalam rentetan yang diberikan dalam PHP menggunakan kaedah yang berbeza. Vokal dalam bahasa Inggeris adalah a, e, i, o, u, dan mereka boleh menjadi huruf besar atau huruf kecil. Apa itu vokal? Vokal adalah watak abjad yang mewakili sebutan tertentu. Terdapat lima vokal dalam bahasa Inggeris, termasuk huruf besar dan huruf kecil: a, e, i, o, u Contoh 1 Input: String = "TutorialSpoint" Output: 6 menjelaskan Vokal dalam rentetan "TutorialSpoint" adalah u, o, i, a, o, i. Terdapat 6 yuan sebanyak 6

Terangkan pengikatan statik lewat dalam php (statik: :). Terangkan pengikatan statik lewat dalam php (statik: :). Apr 03, 2025 am 12:04 AM

Mengikat statik (statik: :) Melaksanakan pengikatan statik lewat (LSB) dalam PHP, yang membolehkan kelas panggilan dirujuk dalam konteks statik dan bukannya menentukan kelas. 1) Proses parsing dilakukan pada masa runtime, 2) Cari kelas panggilan dalam hubungan warisan, 3) ia boleh membawa overhead prestasi.

Apakah kaedah Magic PHP (__construct, __destruct, __call, __get, __set, dll) dan menyediakan kes penggunaan? Apakah kaedah Magic PHP (__construct, __destruct, __call, __get, __set, dll) dan menyediakan kes penggunaan? Apr 03, 2025 am 12:03 AM

Apakah kaedah sihir PHP? Kaedah sihir PHP termasuk: 1. \ _ \ _ Membina, digunakan untuk memulakan objek; 2. \ _ \ _ Destruct, digunakan untuk membersihkan sumber; 3. \ _ \ _ Call, mengendalikan panggilan kaedah yang tidak wujud; 4. \ _ \ _ Mendapatkan, melaksanakan akses atribut dinamik; 5. \ _ \ _ Set, melaksanakan tetapan atribut dinamik. Kaedah ini secara automatik dipanggil dalam situasi tertentu, meningkatkan fleksibiliti dan kecekapan kod.

See all articles