Wenn Sie in Python oder anderen Sprachen arbeiten, sollten Sie mit Generatoren vertraut sein. Viele PHP-Entwickler sind sich der Funktionalität von Generatoren jedoch möglicherweise nicht bewusst, entweder weil Generatoren in PHP 5.5.0 eingeführt wurden oder weil ihre Funktionalität nicht offensichtlich ist. Aber die Generatorfunktion ist wirklich nützlich.
Vorteile
Wenn ich direkt über das Konzept spreche, denke ich, dass Sie nach dem Anhören immer noch verwirrt sein werden. Sprechen wir also zuerst über die Vorteile. Vielleicht kann es das wecken Sie Ihr Interesse. Was sind also die folgenden Vorteile von Generatoren:
● Generatoren haben einen großen Einfluss auf die Leistung von PHP-Anwendungen
● Sparen Sie viel Speicher, wenn PHP-Code ausgeführt wird
● Besser geeignet für die Berechnung großer Datenmengen
Wie werden diese magischen Funktionen erreicht? Lassen Sie uns zunächst ein Beispiel geben.
Konzepteinführung
Lassen Sie uns zunächst die Last des Generatorkonzepts niederlegen und uns eine einfache PHP-Funktion ansehen:
function createRange($number){ $data = []; for($i=0;$i<$number;$i++){ $data[] = time(); } return $data; }
Das ist Eine sehr verbreitete PHP-Funktion, die wir häufig bei der Verarbeitung einiger Arrays verwenden. Auch hier ist der Code sehr einfach:
1. Wir erstellen eine Funktion.
2. Die Funktion enthält eine for-Schleife. Wir fügen die aktuelle Zeit in $data ein.
3 Nachdem die for-Schleife ausgeführt wurde, wird $data zurückgegeben.
Es ist noch nicht vorbei, lasst uns weitermachen. Schreiben wir eine weitere Funktion und geben den Rückgabewert dieser Funktion in einer Schleife aus:
$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1);//这里停顿1秒,我们后续有用 echo $value.'<br />'; }
Schauen wir uns die laufenden Ergebnisse im Browser an:
Das ist sehr perfekt, keinerlei Probleme. (Natürlich kann man den Effekt von Sleep(1) nicht sehen)
Denken Sie über eine Frage nach
Uns ist aufgefallen, dass beim Aufruf der Funktion createRange der Wert übergeben wurde zu $number ist 10, eine sehr kleine Zahl. Angenommen, wir übergeben nun einen Wert von 10000000 (10 Millionen).
Dann muss in der Funktion createRange die for-Schleife 10 Millionen Mal ausgeführt werden. Und 10 Millionen Werte werden in $data abgelegt, und das $data-Array wird im Speicher abgelegt. Daher wird beim Aufrufen von Funktionen viel Speicher belegt.
Hier kann der Generator ins Spiel kommen.
Generator erstellen
Wir ändern den Code direkt, bitte achten Sie darauf:
function createRange($number){ for($i=0;$i<$number;$i++){ yield time(); } }
Sehen Sie sich diesen Code an, der dem gerade sehr ähnlich ist, wir lösche es Array $data und habe nichts zurückgegeben, sondern ein Schlüsselwort yield
vor time() mit dem Generator
verwendet. Lass es uns noch einmal ausführen. Der zweite Teil von Code:
$result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1); echo $value.'<br />'; }
Wir haben auf wundersame Weise festgestellt, dass der Ausgabewert anders ist als beim ersten Mal ohne Verwendung des Generators. Die Werte (Zeitstempel) sind hier im Abstand von 1 Sekunde getrennt.
Das Ein-Sekunden-Intervall hier ist eigentlich das Ergebnis des Schlafs(1). Aber warum gibt es beim ersten Mal keine Lücke? Das liegt daran:
● Wenn der Generator nicht verwendet wird: Das Ergebnis der for-Schleife in der Funktion „createRange“ wird schnell in $data abgelegt und sofort zurückgegeben. Daher ist die foreach-Schleife ein festes Array.
● Bei Verwendung eines Generators: Der Wert von createRange wird nicht schnell auf einmal generiert, sondern hängt von der foreach-Schleife ab. foreach-Schleifen durchlaufen einmal und for werden einmal ausgeführt.
An diesem Punkt sollten Sie eine Vorstellung von Generatoren haben.
Umfassendes Verständnis des Generators
Code-Analyse
Lassen Sie uns jetzt den Code analysieren.
function createRange($number){ for($i=0;$i<$number;$i++){ yield time(); } } $result = createRange(10); // 这里调用上面我们创建的函数 foreach($result as $value){ sleep(1); echo $value.'<br />'; }
Lassen Sie uns den Codeausführungsprozess wiederherstellen.
1. Rufen Sie zuerst die Funktion „createRange“ auf und übergeben Sie dabei Parameter 10. Der for-Wert wird jedoch einmal ausgeführt und stoppt dann und teilt foreach den Wert mit, der für die erste Schleife verwendet werden kann.
2.foreach beginnt mit der Schleife über $result, zuerst Sleep(1) und beginnt dann, einen von for angegebenen Wert für die Ausgabe zu verwenden.
3.foreach bereitet sich auf die zweite Schleife vor, bevor die zweite Schleife gestartet wird.
4. Die for-Schleife wird erneut ausgeführt und teilt foreach den generierten Zeitstempel mit.
5. Aufgrund von Sleep(1) in foreach wird die for-Schleife um 1 Sekunde verzögert, um die aktuelle Zeit zu generieren
Daher ist während der gesamten Codeausführung immer nur ein Datensatzwert an der Schleife beteiligt, und Es gibt nur eine Information im Gedächtnis.
Egal wie groß die $number anfänglich übergeben wird, da nicht alle Ergebnismengen sofort generiert werden, ist der Speicher immer eine Schleife von Werten.
Konzeptionelles Verständnis
An diesem Punkt sollten Sie ein grobes Verständnis davon haben, was ein Generator ist. Lassen Sie uns im Folgenden über das Generatorprinzip sprechen.
Lassen Sie uns zunächst ein Konzept klären: Das Schlüsselwort yield des Generators ist kein Rückgabewert. Sein Fachbegriff heißt Ausgabewert.
Was ist das? die foreach-Schleife im Code? Wenn PHP einen Generator verwendet, gibt es tatsächlich ein Objekt der Generator-Klasse zurück. foreach kann das Objekt iterieren. Für jede Iteration berechnet PHP den Wert, der als nächstes durch die Generator-Instanz iteriert werden muss. Auf diese Weise kennt foreach den Wert, der als nächstes iteriert werden muss.
而且,在运行中for循环执行后,会立即停止。等待foreach下次循环时候再次和for索要下次的值的时候,for循环才会再执行一次,然后立即再次停止。直到不满足条件不执行结束。
实际开发应用
很多PHP开发者不了解生成器,其实主要是不了解应用领域。那么,生成器在实际开发中有哪些应用?
读取超大文件
PHP开发很多时候都要读取大文件,比如csv文件、text文件,或者一些日志文件。这些文件如果很大,比如5个G。这时,直接一次性把所有的内容读取到内存中计算不太现实。
这里生成器就可以派上用场啦。简单看个例子:读取text文件
我们创建一个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 />'; }
通过上图的输出结果我们可以看出代码完全正常。
但是,背后的代码执行规则却一点儿也不一样。使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。
这样,即使读取上G的文本也不用担心,完全可以像读取很小文件一样编写代码。
批量更新数据库表字段
/** * @desc: 方法描述 * @param int $count 数组个数(需要循环多少次) * @param int $limit 数组大小 * @return \Generator */ public function getAddressContent($count = 1, $limit = 20000) { for ($i = 0; $i < ceil($count / $limit); $i++) { $result = StudentModel::where('id','<','67265') ->limit($i * $limit, $limit) ->order('id desc') ->select()->toArray(); yield $result; } } /** * @desc: 修改数据库 省份、城市 * @throws Exception */ public function idCard() { $count = 200000000; // 需要更新的数据 foreach ($this->getAddressContent($count) as $key=>$lists) { foreach ($lists as $k => $v) { $peopleIdentity = new Identity($v['idcard']); $peopleRegion = $peopleIdentity->region(); if($peopleRegion->code() != 0 ){ $res = StudentModel::where('id', $v['id'])->update([ 'birthday' => $peopleIdentity->birthday()??'', 'province' => $peopleRegion->province()??'', 'city' => $peopleRegion->city()??'', 'county' => $peopleRegion->county()??'', ]); Log::debug('更新结果 [' . $v['id'] . ']: ' . json_encode($res)); } } } echo "success"; }
使用命令行执行
php id_card.php
打印日志
CPU和内存消耗
更多php知识,请访问php教程!
Das obige ist der detaillierte Inhalt vonPHP-Leistungsoptimierungstool: Generator. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!