cari
Rumahpembangunan bahagian belakangtutorial php带你详解PHP生成器的使用

带你详解PHP生成器的使用

Dec 01, 2020 pm 01:50 PM
penjana php

学习PHP生成器的使用

什么是生成器?

听着高大上的名字,感觉像是创造什么东西的一个功能,实际上,生成器是一个用于迭代的迭代器。它提供了一种更容易的方式来实现简单的对象迭代,相比较定义类实现Iterator接口的方式,性能开销和复杂性大大降低。

推荐:《PHP视频教程

说了半天不如直接看看代码更直观。

function test1()
{
    for ($i = 0; $i < 3; $i++) {
        yield $i + 1;
    }
    yield 1000;
    yield 1001;
}
foreach (test1() as $t) {
    echo $t, PHP_EOL;
}
// 1
// 2
// 3
// 1000
// 1001

就是这么简单的一段代码。首先,生成器必须在方法中并使用 yield 关键字;其次,每一个 yield 可以看作是一次 return ;最后,外部循环时,一次循环取一个 yield 的返回值。在这个例子,循环三次返回了1、2、3这三个数字。然后在循环外部又写了两行 yield 分别输出了1000和1001。因此,外部的 foreach 一共循环输出了五次。

很神奇吧,明明是一个方法,为什么能够循环它而且还是很奇怪的一种返回循环体的格式。我们直接打印这个 test() 方法看看打印的是什么:

// 是一个生成器对象
var_dump(test1());
// Generator Object
// (
// )

当使用了 yield 进行内容返回后,返回的是一个 Generator 对象。这个对象就叫作生成器对象,它不能直接被 new 实例化,只能通过生成器函数这种方式返回。这个类包含 current() 、 key() 等方法,而且最主要的这个类实现了 Iterator 接口,所以,它就是一个特殊的迭代器类。

Generator implements Iterator {
    /* 方法 */
    public current ( void ) : mixed
    public key ( void ) : mixed
    public next ( void ) : void
    public rewind ( void ) : void
    public send ( mixed $value ) : mixed
    public throw ( Exception $exception ) : void
    public valid ( void ) : bool
    public __wakeup ( void ) : void
}

生成器有什么用?

搞了半天不就是个迭代器嘛?搞这么麻烦干嘛,直接用迭代器或者在方法中直接返回一个数组不就好了吗?没错,正常情况下真的没有这么麻烦,但是如果是在数据量特别大的情况下,这个生成器就能发挥它的强大威力了。生成器最最强大的部分就在于,它不需要一个数组或者任何的数据结构来保存这一系列数据。每次迭代都是代码执行到 yield 时动态返回的。因此,生成器能够极大的节约内存。

// 内存占用测试
$start_time = microtime(true);
function test2($clear = false)
{
    $arr = [];
    if($clear){
        $arr = null;
        return;
    }
    for ($i = 0; $i < 1000000; $i++) {
        $arr[] = $i + 1;
    }
    return $arr;
}
$array = test2();
foreach ($array as $val) {
}
$end_time = microtime(true);
echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL;
echo "memory (byte): ", memory_get_usage(true), PHP_EOL;
// time: 0.0513
// memory (byte): 35655680
$start_time = microtime(true);
function test3()
{
    for ($i = 0; $i < 1000000; $i++) {
        yield $i + 1;
    }
}
$array = test3();
foreach ($array as $val) {
}
$end_time = microtime(true);
echo "time: ", bcsub($end_time, $start_time, 4), PHP_EOL;
echo "memory (byte): ", memory_get_usage(true), PHP_EOL;
// time: 0.0517
// memory (byte): 2097152

上述代码只是简单的进行 1000000 个循环后获取结果,不过也可以直观地看出。使用生成器的版本仅仅消耗了 2M 的内存,而未使用生成器的版本则消耗了 35M 的内存,直接已经10多倍的差距了,而且越大的量差距超明显。因此,有大神将生成器说成是PHP中最被低估了的一个特性。

生成器的应用

接下来我们来看看生成器的一些基本的应用方式。

返回空值以及中断

生成器当然也可以返回空值,直接 yield; 不带任何值就可以返回一个空值了。而在方法中直接使用 return; 也可以用来中断生成器的继续执行。下面的代码我们在 $i = 4; 的时候返回的是个空值,也就是不会输出 5 (因为我们返回的是 $i + 1 )。然后在 $i == 7 的时候

使用 return; 中断生成器的继续执行,也就是循环最多只会输出到 7 就结束了。

// 返回空值以及中断
function test4()
{
    for ($i = 0; $i < 10; $i++) {
        if ($i == 4) {
            yield; // 返回null值
        }
        if ($i == 7) {
            return; // 中断生成器执行
        }
        yield $i + 1;
    }
}
foreach (test4() as $t) {
    echo $t, PHP_EOL;
}
// 1
// 2
// 3
// 4
// 5
// 6
// 7

返回键值对形式

不要惊讶,生成器真的是可以返回键值对形式的可遍历对象供 foreach 使用的,而且语法非常好记: yield key => value; 是不是和数组项的定义形式一模一样,非常直观好理解。

function test5()
{
    for ($i = 0; $i < 10; $i++) {
        yield &#39;key.&#39; . $i => $i + 1;
    }
}
foreach (test5() as $k=>$t) {
    echo $k . &#39;:&#39; . $t, PHP_EOL;
}
// key.0:1
// key.1:2
// key.2:3
// key.3:4
// key.4:5
// key.5:6
// key.6:7
// key.7:8
// key.8:9
// key.9:10

外部传递数据

我们可以通过 Generator::send 方法来向生成器中传入一个值。传入的这个值将会被当做生成器当前 yield 的返回值。然后我们根据这个值可以做一些判断,比如根据外部条件中断生成器的执行。

function test6()
{
    for ($i = 0; $i < 10; $i++) {
        // 正常获取循环值,当外部send过来值后,yield获取到的就是外部传来的值了
        $data = (yield $i + 1);
        if($data == &#39;stop&#39;){
            return;
        }
    }
}
$t6 = test6();
foreach($t6 as $t){
    if($t == 3){
        $t6->send(&#39;stop&#39;);
    }
    echo $t, PHP_EOL;
}
// 1
// 2
// 3

上述代码理解起来可能比较绕,但是注意记住注释的那行话就行了(正常获取循环值,当外部send过来值后,yield获取到的就是外部传来的值了)。另外,变量获取 yield 的值,必须要用括号括起来。

yield from 语法

yield from 语法其实就是指的从另一个可迭代对象中一个一个的获取数据并形成生成器返回。直接看代码。

function test7()
{
    yield from [1, 2, 3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from test1();
}
foreach (test7() as $t) {
    echo &#39;test7:&#39;, $t, PHP_EOL;
}
// test7:1
// test7:2
// test7:3
// test7:4
// test7:5
// test7:6
// test7:1
// test7:2
// test7:3
// test7:1000

在 test7() 方法中,我们使用 yield from 分别从普通数组、迭代器对象、另一个生成器中获取数据并做为当前生成器的内容进行返回。

小惊喜

生成器可以用count获取数量吗?

抱歉,生成器是不能用count来获取它的数量的。

$c = count(test1()); // Warning: count(): Parameter must be an array or an object that implements Countable
// echo $c, PHP_EOL;

使用 count 来获取生成器的数量将直接报 Warning 警告。直接输出将会一直显示是 1 ,因为 count 的特性(强制转换成数组都会显示 1 )。

使用生产器来获取斐波那契数列

// 利用生成器生成斐波那契数列
function fibonacci($item)
{
    $a = 0;
    $b = 1;
    for ($i = 0; $i < $item; $i++) {
        yield $a;
        $a = $b - $a;
        $b = $a + $b;
    }
}
$fibo = fibonacci(10);
foreach ($fibo as $value) {
    echo "$value\n";
}

这段代码就不多解释了,非常直观的一段代码了。

总结

生成器绝对是PHP中的一个隐藏的宝藏,不仅是对于内存节约来说,而且语法其实也非常的简洁明了。我们不需要在方法内部再多定义一个数组去存储返回值,直接 yield 一项一项的返回就可以了。在实际的项目中完全值得尝试一把,但是尝试完了别忘了和小伙伴们分享,大部分人可能真的没有接触过这个特性哦!!

测试代码: https://github.com/zhangyue0503/dev-blog/blob/master/php/202002/source/%E5%AD%A6%E4%B9%A0PHP%E7%94%9F%E6%88%90%E5%99%A8%E7%9A%84%E4%BD%BF%E7%94%A8.php

参考文档: https://www.php.net/manual/zh/language.generators.overview.php https://www.php.net/manual/zh/class.generator.php

Atas ialah kandungan terperinci 带你详解PHP生成器的使用. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Artikel ini dikembalikan pada:zhihu. Jika ada pelanggaran, sila hubungi admin@php.cn Padam
PHP dan Python: Paradigma yang berbeza dijelaskanPHP dan Python: Paradigma yang berbeza dijelaskanApr 18, 2025 am 12:26 AM

PHP terutamanya pengaturcaraan prosedur, tetapi juga menyokong pengaturcaraan berorientasikan objek (OOP); Python menyokong pelbagai paradigma, termasuk pengaturcaraan OOP, fungsional dan prosedur. PHP sesuai untuk pembangunan web, dan Python sesuai untuk pelbagai aplikasi seperti analisis data dan pembelajaran mesin.

PHP dan Python: menyelam mendalam ke dalam sejarah merekaPHP dan Python: menyelam mendalam ke dalam sejarah merekaApr 18, 2025 am 12:25 AM

PHP berasal pada tahun 1994 dan dibangunkan oleh Rasmuslerdorf. Ia pada asalnya digunakan untuk mengesan pelawat laman web dan secara beransur-ansur berkembang menjadi bahasa skrip sisi pelayan dan digunakan secara meluas dalam pembangunan web. Python telah dibangunkan oleh Guidovan Rossum pada akhir 1980 -an dan pertama kali dikeluarkan pada tahun 1991. Ia menekankan kebolehbacaan dan kesederhanaan kod, dan sesuai untuk pengkomputeran saintifik, analisis data dan bidang lain.

Memilih antara php dan python: panduanMemilih antara php dan python: panduanApr 18, 2025 am 12:24 AM

PHP sesuai untuk pembangunan web dan prototaip pesat, dan Python sesuai untuk sains data dan pembelajaran mesin. 1.Php digunakan untuk pembangunan web dinamik, dengan sintaks mudah dan sesuai untuk pembangunan pesat. 2. Python mempunyai sintaks ringkas, sesuai untuk pelbagai bidang, dan mempunyai ekosistem perpustakaan yang kuat.

PHP dan Rangka Kerja: Memodenkan bahasaPHP dan Rangka Kerja: Memodenkan bahasaApr 18, 2025 am 12:14 AM

PHP tetap penting dalam proses pemodenan kerana ia menyokong sejumlah besar laman web dan aplikasi dan menyesuaikan diri dengan keperluan pembangunan melalui rangka kerja. 1.Php7 meningkatkan prestasi dan memperkenalkan ciri -ciri baru. 2. Rangka kerja moden seperti Laravel, Symfony dan CodeIgniter memudahkan pembangunan dan meningkatkan kualiti kod. 3. Pengoptimuman prestasi dan amalan terbaik terus meningkatkan kecekapan aplikasi.

Impak PHP: Pembangunan Web dan seterusnyaImpak PHP: Pembangunan Web dan seterusnyaApr 18, 2025 am 12:10 AM

Phphassignificantelympactedwebdevelopmentandextendsbeyondit.1) itpowersmajorplatformslikeworderpressandexcelsindatabaseIntions.2) php'SadaptabilityAldoStoScaleforlargeapplicationFrameworksLikelara.3)

Bagaimanakah jenis membayangkan jenis PHP, termasuk jenis skalar, jenis pulangan, jenis kesatuan, dan jenis yang boleh dibatalkan?Bagaimanakah jenis membayangkan jenis PHP, termasuk jenis skalar, jenis pulangan, jenis kesatuan, dan jenis yang boleh dibatalkan?Apr 17, 2025 am 12:25 AM

Jenis PHP meminta untuk meningkatkan kualiti kod dan kebolehbacaan. 1) Petua Jenis Skalar: Oleh kerana Php7.0, jenis data asas dibenarkan untuk ditentukan dalam parameter fungsi, seperti INT, Float, dan lain -lain. 2) Return Type Prompt: Pastikan konsistensi jenis nilai pulangan fungsi. 3) Jenis Kesatuan Prompt: Oleh kerana Php8.0, pelbagai jenis dibenarkan untuk ditentukan dalam parameter fungsi atau nilai pulangan. 4) Prompt jenis yang boleh dibatalkan: membolehkan untuk memasukkan nilai null dan mengendalikan fungsi yang boleh mengembalikan nilai null.

Bagaimanakah PHP mengendalikan pengklonan objek (kata kunci klon) dan kaedah sihir __clone?Bagaimanakah PHP mengendalikan pengklonan objek (kata kunci klon) dan kaedah sihir __clone?Apr 17, 2025 am 12:24 AM

Dalam PHP, gunakan kata kunci klon untuk membuat salinan objek dan menyesuaikan tingkah laku pengklonan melalui kaedah Magic \ _ _ _. 1. Gunakan kata kunci klon untuk membuat salinan cetek, mengkloning sifat objek tetapi bukan sifat objek. 2. Kaedah klon \ _ \ _ boleh menyalin objek bersarang untuk mengelakkan masalah menyalin cetek. 3. Beri perhatian untuk mengelakkan rujukan pekeliling dan masalah prestasi dalam pengklonan, dan mengoptimumkan operasi pengklonan untuk meningkatkan kecekapan.

PHP vs Python: Gunakan Kes dan AplikasiPHP vs Python: Gunakan Kes dan AplikasiApr 17, 2025 am 12:23 AM

PHP sesuai untuk pembangunan web dan sistem pengurusan kandungan, dan Python sesuai untuk sains data, pembelajaran mesin dan skrip automasi. 1.PHP berfungsi dengan baik dalam membina laman web dan aplikasi yang cepat dan berskala dan biasanya digunakan dalam CMS seperti WordPress. 2. Python telah melakukan yang luar biasa dalam bidang sains data dan pembelajaran mesin, dengan perpustakaan yang kaya seperti numpy dan tensorflow.

See all articles

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 laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌
Akan R.E.P.O. Ada Crossplay?
1 bulan yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

Muat turun versi mac editor Atom

Muat turun versi mac editor Atom

Editor sumber terbuka yang paling popular

MantisBT

MantisBT

Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

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