Si vous travaillez en Python ou dans d'autres langages, vous devez être familier avec les générateurs. Cependant, de nombreux développeurs PHP peuvent ne pas connaître la fonction générateur. Cela peut être dû au fait que le générateur est une fonction introduite dans PHP 5.5.0, ou que la fonction du générateur n'est pas très évidente. Cependant, la fonction générateur est vraiment utile.
Si je parle directement du concept, je suppose que vous serez encore confus après l'avoir écouté, alors parlons d'abord des avantages, peut-être que cela pourra susciter votre intérêt. Alors quels sont les avantages des générateurs, comme suit :
Alors, comment ces fonctions magiques sont-elles réalisées ? Donnons d'abord un exemple.
Tout d'abord, éliminons le fardeau du concept de générateur et examinons une fonction PHP simple :
function createRange($number){ $data = []; for($i=0;$i<$number;$i++){ $data[] = time(); } return $data; }复制代码
Il s'agit d'une fonction PHP très courante qui nous avons affaire à Il est souvent utilisé lorsque l'on travaille avec certains tableaux. Le code ici est également très simple :
for
Nous bouclons l'heure actuelle dans $data
et for
termine l'exécution de la boucle et renvoie $data
. Ce n’est pas encore fini, continuons. Écrivons une autre fonction et imprimons la valeur de retour de cette fonction dans une boucle :
$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1);//这里停顿1秒,我们后续有用 echo $value.'<br />'; }复制代码
Jetons un coup d'œil aux résultats exécutés dans le navigateur :
![](https:// picb.zhimg .com/80/v2-3620f3d46bb5b49e53ca47891ea1fd5a_720w.jpg)
C'est parfait ici, aucun problème. (Bien sûr, vous ne pouvez pas voir l'effet de sleep(1)
)
Nous avons remarqué que lors de l'appel de la fonction createRange
, la valeur passée à $number
est 10, ce qui est un très petit nombre. Supposons que, maintenant, transmettez une valeur 10000000
(10 millions).
Ensuite, dans la fonction createRange
, la boucle for
doit être exécutée 1000
dix mille fois. Et il y a 1000
dix mille valeurs placées dans $data
, et le tableau $data
est placé dans la mémoire. Par conséquent, beaucoup de mémoire sera occupée lors de l’appel de fonctions.
Ici, le générateur peut entrer en jeu.
On modifie le code directement, merci de faire attention :
function createRange($number){ for($i=0;$i<$number;$i++){ yield time(); } }复制代码
Regardez ce code qui est très similaire à tout à l'heure, nous avons supprimé le tableau$data
, Et il n'a rien renvoyé, mais a utilisé un mot-clé time()
yield
Exécutons à nouveau le deuxième morceau de code :
$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1); echo $value.'<br />'; }复制代码
![](https://pic2.zhimg.com/80/v2-9c08f2d01f7a68736f45ffa3d3934cc5_720w.jpg)
Nous avons miraculeusement découvert que la valeur de sortie est la même que la première fois sans utiliser le générateur, pas la même . Les valeurs (horodatages) ici sont séparées de 1 seconde.
L'intervalle d'une seconde ici est en fait la conséquence de sleep(1)
. Mais pourquoi n’y a-t-il pas d’écart la première fois ? En effet :
createRange
au sein de la fonction for
est rapidement placé dans $data
et renvoyé immédiatement. Par conséquent, foreach
parcourt un tableau fixe. createRange
n'est pas générée rapidement en une seule fois, mais s'appuie sur la boucle foreach
. foreach
Bouclez une fois et for
exécutez une fois. À ce stade, vous devriez avoir une idée du générateur.
Analysons le code tout à l'heure.
function createRange($number){ for($i=0;$i<$number;$i++){ yield time(); } } $result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1); echo $value.'<br />'; }复制代码
Restaurons le processus d'exécution du code.
createRange
, en passant le paramètre 10
, mais la valeur for
est exécutée une fois puis arrêtée, et indique à foreach
la valeur qui peut être utilisée pour la première boucle. foreach
commence à boucler sur $result
, arrivant en premier sleep(1)
, puis commence à effectuer une sortie en utilisant une valeur donnée par for
. foreach
prépare la deuxième boucle Avant de démarrer la deuxième boucle, il demande à nouveau la boucle for
. La boucle for
est ensuite exécutée à nouveau et l'horodatage généré est envoyé à foreach
.foreach
pour obtenir la deuxième valeur et la générer. Puisque foreach
est dans sleep(1)
, la boucle for
est retardée d'1 seconde pour générer l'heure actuelle Par conséquent, pendant toute l'exécution du code, il n'y a toujours qu'une seule valeur d'enregistrement. participant à la boucle, et il n’y a qu’une seule valeur d’enregistrement dans la mémoire Un message.
Peu importe la taille du $number
initialement transmis, puisque tous les jeux de résultats ne sont pas générés immédiatement, la mémoire est toujours une boucle de valeurs.
À ce stade, vous devriez avoir une compréhension approximative de ce qu'est un générateur. Parlons ci-dessous du principe du générateur.
首先明确一个概念:生成器yield关键字不是返回值,他的专业术语叫产出值,只是生成一个值
那么代码中foreach
循环的是什么?其实是PHP在使用生成器的时候,会返回一个Generator
类的对象。foreach
可以对该对象进行迭代,每一次迭代,PHP会通过Generator
实例计算出下一次需要迭代的值。这样foreach
就知道下一次需要迭代的值了。
而且,在运行中for
循环执行后,会立即停止。等待foreach
下次循环时候再次和for
索要下次的值的时候,for
循环才会再执行一次,然后立即再次停止。直到不满足条件不执行结束。
很多PHP开发者不了解生成器,其实主要是不了解应用领域。那么,生成器在实际开发中有哪些应用?
PHP开发很多时候都要读取大文件,比如csv文件、text文件,或者一些日志文件。这些文件如果很大,比如5个G。这时,直接一次性把所有的内容读取到内存中计算不太现实。
这里生成器就可以派上用场啦。简单看个例子:读取text文件
![](https://pic1.zhimg.com/80/v2-2d6fb1058b39008fbe4e5363e485e9a2_720w.jpg)
我们创建一个text文本文档,并在其中输入几行文字,示范读取。
<?php header("content-type:text/html;charset=utf-8"); function readTxt() { # code... $handle = fopen("./test.txt", 'rb'); while (feof($handle)===false) { # code... yield fgets($handle); } fclose($handle); } foreach (readTxt() as $key => $value) { # code... echo $value.'<br />'; }复制代码
![](https://pic4.zhimg.com/80/v2-2bbdc40ebf8f1aeedf2aa0c472811c77_720w.jpg)
通过上图的输出结果我们可以看出代码完全正常。
但是,背后的代码执行规则却一点儿也不一样。使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。
这样,即使读取上G的文本也不用担心,完全可以像读取很小文件一样编写代码。
想了解更多编程学习,敬请关注php培训栏目!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!