이 기사에서는 foreach
, for
, while이 없는 생성기에서 PHP Yield를 사용하는 방법에 대해 논의하고 싶습니다.
루프의 종류입니다. 함수를 생성기로 변환하기 위해 yield
를 사용하는 방법을 논의해 보겠습니다. foreach
,for
, while
循环的那种。就讨论 yield
将一个函数变成为生成器的用法。
关于
yield
特性,是在开发PHP5
时被提上日程,PHP5.5
版本正式加入。
关于yield
的使用,我看到大部分文章都停留在,使用yield
如何在foreach
中穿出数据,今天想给大家讲讲 生成器 所有语法。
相关学习推荐:PHP编程从入门到精通
生成器允许你在 foreach
代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield
多次,以便生成需要迭代的值。
看了下官网对他讲解:php.net 生成器语法 . 每个字都认识,但似乎还是体会到它讲的内涵。官网我们主要看两部分内容:
yield
的语法。
代码例子。
先说语法, yield 的左边是一个赋值语句,右边可以是值(也可是表达式) 。而yield 会先执行右边的表达式,并把值$value送到生成器外面。当生成器收到值后,会执行yield左边的语句,赋值给$data.
<?phpfunction func(){ $data = (yield [$express]);}
语法就这样,估计大家还是有些懵,那就看看官网下面代码例子吧,我看里面例子参差不齐。
注意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,用来检查哪些函数能构成生成器,哪些不能。运行结果如下
yield
关键词,函数可以是全剧函数,或者类的方法。yield
肯定不会被执行,也会产生生成器。见:yield_func4yield
关键词就行(不向外送出,不处理外面的输入)。见: yield_func2yield
会报错, 见:yield_func11是的,函数内有没有foreach,while,for 语句都不是关键,关键是 yield. 生成器的类型判断用
$gen instanceof Generator
yield
기능과 관련하여, PHP5
개발 시 안건으로 제기되었고, PHP5.5
버전이 정식 추가되었습니다. yield
사용과 관련하여 오늘 foreach
에서 yield
를 사용하여 데이터를 소모하는 방법에 대해 대부분의 기사가 붙어 있는 것을 봤습니다. 제너레이터의 모든 구문을 알려드리고 싶습니다. 🎜 🎜공식 웹사이트 설명🎜🎜생성기를 사용하면foreach
코드 블록에 코드를 작성하여 메모리에 배열을 생성하지 않고도 데이터 세트를 반복할 수 있습니다. 이로 인해 메모리가 상한에 도달하거나 상당한 공간을 차지하게 됩니다. 처리 시간. 대신 일반 사용자 정의 함수와 마찬가지로 생성기 함수를 작성할 수 있으며, 한 번만 반환하는 일반 함수 대신 생성기가 값을 반복해야 할 만큼 생성기가 필요한 만큼생성
할 수 있습니다. . 🎜🎜공식 웹사이트를 보고 그에게 설명했습니다: php.net 생성기 구문 저는 모든 단어를 알고 있었지만 여전히 그 의미를 이해하는 것 같았습니다. 공식 웹사이트에서는 주로 🎜🎜 먼저 구문에 대해 이야기해 보겠습니다. 항복의 왼쪽은 대입문이고 오른쪽은 값(또는 표현식)이 될 수 있습니다. Yield는 먼저 오른쪽의 표현식을 실행하고 $value 값을 생성기 외부로 보냅니다. 생성기가 값을 받으면 Yield 왼쪽에 있는 명령문을 실행하고 $data에 값을 할당합니다.🎜
- 🎜
yield
구문 두 부분을 살펴봅니다. 🎜- 🎜코드 예시. 🎜
<?phpfunction yield_func(){ yield 12; return 'a';}$gen = yield_func();$re = $gen->current();echo 'current return : ' . $re;🎜 구문은 아직 다들 헷갈리는 것 같으니 코드를 살펴보세요. 공식 웹 사이트 아래의 예는 고르지 않은 것 같습니다. 🎜🎜🎜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, 생성기를 구성할 수 있는 함수와 생성할 수 없는 함수를 확인하는 데 사용됩니다. 실행 결과는 다음과 같습니다🎜🎜🎜🎜🎜예, 함수에 foreach, while 및 for 문이 있는지 여부가 핵심이 아닙니다.
yield
키워드는 함수에 포함되어야 합니다. 함수는 전체 함수이거나 클래스 메서드일 수 있습니다.yield
가 반드시 실행되지 않더라도 제너레이터는 생성됩니다. 참고: Yield_func4- 기본
yield
키워드만 사용하면 됩니다(전송 없음, 외부 입력 처리 없음). 참조: Yield_func2- 함수 내에서 생성기를 사용한다고 해서 그 자체가 생성기가 되는 것은 아닙니다. 참조: Yield_func5
- 평가 함수에서 직접
yield
를 실행하면 다음이 보고됩니다. 오류, 참조: Yield_func11$gen 인스턴스 생성기를 사용하세요. >🎜🎜🎜🎜🎜Generator 함수🎜🎜Generator 개체는 생성기에서 반환됩니다.🎜🎜🎜Generator 개체는 new를 통해 인스턴스화할 수 없습니다.🎜
摘自 php.net generator
看着以上方法,是不想起了
Iterator
, 他们的确很像。同时注意,官网zh语言版本的文档没有索引方法getReturn
,访问也是404。文档以en版为准,ch做参考。
以上就是生成器所有的方法,我们一个个来看。
测试方法代码 /php-yield-test/generatorMothod.php, 这里面对每个方法都有使用举例,运行结果如下。
好接下来对举例做个一一讲解。
<?phpfunction yield_func(){ yield 12; return 'a';}$gen = yield_func();$re = $gen->current();echo 'current return : ' . $re;
输出:
current return : 12
看到 php-yield-test/generatorMothod.php
代码。
通过第一个代码事例,可得,对一个generator调用current方法,才算真正开始执行。执行到yield为止。如果不能命中yield,则执行到函数结束。
非generoator会立马执行并得到结果,而非一个生成器对象。
通过例子2,调用current一次,两次呢,第一次可以看到代码执行日志,第二次,只是把上一次的结果返回给我们而已,并不是让该生成器重新执行。
通过例子1,调用该函数还会获取到返回值,返回的内容就是 yield 表达式左边的内容。如果表达式无内容,则是NULL.
yield
点中传入一个值,并返回下一次current
值。<?phpfunction yield_func(){ $data = yield 12; echo 'get yield data: ' . $data; return 'a';}$gen = yield_func();$re = $gen->current();$gen->send(32);
输出:
get yield data: 32
例子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 'run to code line: ' . __LINE__ . PHP_EOL; yield; echo 'run to code line: ' . __LINE__ . PHP_EOL; return $result;}$gen = yield_func();$gen->current();echo 'current called' . PHP_EOL;$gen->next();
输出:
run to code line: 4current called run to code line: 6
例子5,这是一个较为常规的调用,调用current
代码运行yield
等到用户输入,这是调用next跳过,让代码继续运行。
例子6,直接调用next
,相当于调用current
,next
。而且通过最后打印$result
, 我们发现怎么有点像在调用 $gen->send(NULL);
。
<?phpfunction yield_func(){ echo 'run to code line: ' . __LINE__ . PHP_EOL; $result = yield 12; echo 'run to code line: ' . __LINE__ . PHP_EOL;}$gen = yield_func();echo 'call yield_func rewind ' . PHP_EOL;$gen->rewind();
输出:
call yield_func rewind run to code line: 4
例子7,8 中,发现调用该方法,会导致隐式调用current
。
例子9 中,发现在执行过一个yield代码段后,再次调用该方法,会导致报错(哪怕该 生成器已结束)。
<?phpfunction yield_func(){ try { $re = yield 'exception'; } catch (Exception $e) { echo 'catched exception msg: ' .$e->getMessage(); }}$gen = yield_func();$gen->throw(new \Exception('new yield exception'));
输出:
catched exception msg: new yield exception
通过以上简单的例子可得,throw 就是让yield这行代码产生异常,让外面的try catch 捕获我们生成的那个异常。
例子11中,构造生成器,并调用current方法,运行到yield处,再调用throw,就能捕获到异常。
例子12中,当调用send方法,跳过函数内yield代码时,再调用throw传入异常,就没法捕获了。
<?phpfunction yield_func(){ yield 12; return 'a';}$gen = yield_func();$gen->send(1);$check = $gen->valid();echo 'the generator valid ? ' . intval($check);
输出:
the generator valid ? 0
例子12中,发现current被隐式调用。
例子13中,可得,当生成器运行到yield代码段时,用valid
函数检查,都会返回true
。
所以,别问我是否已运行,问就是运行。该方法用来获取是否关闭状态,不是 是否运行状态!运行到底,运行到return就是 关闭状态。
<?phpfunction yield_func(){ yield 1 => 'abc';}$gen = yield_func();echo 'value is :' . $gen->current() . PHP_EOL;echo 'key is: ' . $gen->key() . PHP_EOL;
输出:
value is :abc key is: 1
从以上例子中,可得yield可显示设置返回的key.
例子15 中,发现key的分发规律和PHP数组键值发放策略是差不多的,默认从0开始,未指定则是以上一个数字key+1
作为当前的key
.
例子16 中,我们又发现current
被隐式调用。
<?phpfunction yield_func(){ yield 1 => 'abc';}$gen = yield_func();try {$ser = serialize($gen);} catch (\Exception $e) { print_r($e->getMessage());}
输出:
Serialization of 'Generator' is not allowed
这是一个魔术方法,见 PHP 魔术方法,也就是说 生成器 不能被序列化成一个字符串。
例子17就不用说了,看下例子18,看样子序列化成功了。也就是说一个生成器做为一个方法可以被序列化,当函数变成生成器时,就不能被序列化了。
<?phpfunction yield_func(){ yield 1 => 'abc'; return 32;}$gen = yield_func();$gen->send(0);echo 'call yield_func return, and get: ' . $gen->getReturn();
输出:
call yield_func return, and get: 32
该函数就是获取生成器最后的返回值。如果没有return语句,或者没有执行到return语句,调用该函数得到的就是NULL。
例子19 可得,getReturn 能够获取到生成器最后的返回值。
例子19、20 可得,当生成器没有执行到return语句,或者没有执行到最后时,调用getReturn是会导致报错。
到这里,我们就发现rewind
,next
和 __wakeup
这两个函数感觉没啥叼用呢,为啥还存在呢,因为Generator
继承Iterator
,自然就有了rewind
, next
方法,PHP
虽然支持方法覆盖,但子类的访问修饰符
不能缩紧,所以Generator
只能重写这两个方法。 __wakeup
继承自 stdClass
。
看图:
PHP yield 生命周期图
画了两个状态转换图,上面的要细致,繁复一点。下面的精简版,便于快速理解。
以上就是关于 PHP 生成器的基础内容,希望你看了后对它有更进一步认识。下一讲,我们手把手一起来做一个任务调度器,实战一下。
有问题欢迎提问,谢谢大家!
위 내용은 PHP 항복 코루틴 생성기 사용법 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!