Bir üreteç işlevi, normal bir işlev gibi görünür fakat bir üreteç tek bir değer döndürmek yerine ihtiyaç duyulduğu kadar çok değer üretir (yield). yield içeren her işlev bir üreteç işlevidir.
Bir üreteç işlevi çağrıldığında üzerinde yineleme yapılabilecek bir nesne döndürür. Bu nesne üzerinde yineleme yaptığınızda (örneğin foreach ile), PHP bir değere her ihtiyaç duyuşunda nesnenin yineleme yöntemlerini çağırır ve üreteç bir değer ürettiğinde üretecin durumunu kaydeder, böylece yeni bir değere her ihtiyaç duyuluşunda üreteç kaldığı yerden devam edebilir.
Üretilecek değer kalmadığında, üreteç basitçe çıkar ve adeta bir dizi değerlerini tüketmiş gibi kod çağrılmaya devam eder.
Bilginize:
Bir üreteç değer döndürebilir ve Generator::getReturn() kullanılarak alınabilir.
Üreteç işlevinin kalbi yield sözcüğüdür. En basit halinde, bir yield deyimi çoğunlukla bir return deyimi gibi görünür. İşlevin çalışmasını durdurmak ve değer döndürmek yerine, yield, üreteç üzerindeki kod döngüsüne bir değer verir ve üreteç işlevini bekletir.
Örnek 1 - Basit bir yield örneği
<?php
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// yield'ler arasında $i korunur.
yield $i;
}
}
$generator = gen_one_to_three();
foreach ($generator as $value) {
echo "$value\n";
}
?>
Yukarıdaki örneğin çıktısı:
1 2 3
Bilginize:
Dahili olarak, ilişkisel olmayan dizilerdeki gibi sıralı tamsayı anahtarlar üretilen (yield) değerlerle çiftler oluşturur.
PHP ilişkisel dizileri de destekler ve üreteçlerin bir farkı yoktur. Basit değerlerin üretilmesinin yanında, yukarıda gösterildiği gibi, aynı anda bir anahtar da üretebilirsiniz.
Bir anahtar/değer çifti üretmenin (yielding) sözdizimi, aşağıda gösterildiği gibi, bir ilişkisel dizi tanımlamada kullanılan sözdizimine çok benzer.
Örnek 2 - Bir anahtar/değer çifti üretimi
<?php
/*
* girdi noktalı virgülle ayrılmış alanlardır,
* ilk alan anahtar olarak kullanılacak ID'dir
*/
$input = <<<'EOF'
1;PHP;Dolar imlerini sever
2;Python;Boşlukları sever
3;Ruby;Blokları sever
EOF;
function input_parser($input) {
foreach (explode("\n", $input) as $line) {
$fields = explode(';', $line);
$id = array_shift($fields);
yield $id => $fields;
}
}
foreach (input_parser($input) as $id => $fields) {
echo "$id:\n";
echo " $fields[0]\n";
echo " $fields[1]\n";
}
?>
Yukarıdaki örneğin çıktısı:
1: PHP Dolar imlerini sever 2: Python Boşlukları sever 3: Ruby Blokları sever
Yield deyimini bağımsız değişkensiz kullanmak null
değerinin otomatik bir
anahtarla birlikte üretilmesini sağlar.
Örnek 3 - null
üretmek
<?php
function gen_three_nulls() {
foreach (range(1, 3) as $i) {
yield;
}
}
var_dump(iterator_to_array(gen_three_nulls()));
?>
Yukarıdaki örneğin çıktısı:
array(3) { [0]=> NULL [1]=> NULL [2]=> NULL }
Üreteç işlevleri üretimi, değerlerle yapabildiği gibi başvurularla da yapabilir. Bu, işlev isminin önüne bir '&' imi yerleştirip işlevlerden başvurları döndürerek yapılabilir:
Örnek 4 - Değerleri başvuruya göre üretmek
<?php
function &gen_reference() {
$value = 3;
while ($value > 0) {
yield $value;
}
}
/*
* $number döngü içinde değiştirilebilir,
* üreteç başvuruları ürettiğinden,
* gen_reference() içindeki $value değişir.
*/
foreach (gen_reference() as &$number) {
echo (--$number).'... ';
}
?>
Yukarıdaki örneğin çıktısı:
2... 1... 0...
Üreteç ihalesi, değerlerin başka bir üreteçte, Traversable nesnesinden veya yield from anahtar sözcüğü kullanılarak bir diziden üretilmesini sağlar. Dış üreteç tüm değerleri iç üreteç, nesne veya diziden geçerliliğini yitirene kadar ürettikten sonra üretime dış üreteçte devam edecektir.
Bir üreteç yield from ile kullanılırsa, yield from ifadesi ayrıca, iç üreteçten döndürülen değerleri de döndürecektir.
yield from anahtarları sıfırlamaz, Traversable nesnesinden veya diziden döndürülen anahtarları korur. Böylece, bazı değerler başka bir yield veya yield from ile ortaklaşılan bir anahtarla paylaşılır (bir diziye değer girilmesiyle, anahtar ilk değerlerin üzerine yazılmasına sebep olur).
Bu konuda alışılmış durum, iterator_to_array()
işlevinin öntanımlı olarak bir anahtarlı dizi döndürmesidir
(muhtemelen beklenmedik sonuçlara yol açarak).
iterator_to_array() ikinci bir bağımsız değişkene
sahiptir: Generator tarafından döndürülen
anahtarları yoksayarken tüm değerleri toplamak için false
atanabilen
preserve_keys
bağımsız değişkeni.
Örnek 5 - iterator_to_array() ile yield from
<?php
function inner() {
yield 1; // key 0
yield 2; // key 1
yield 3; // key 2
}
function gen() {
yield 0; // key 0
yield from inner(); // keys 0-2
yield 4; // key 1
}
// [0, 1, 2, 3, 4] dizisini almak için ikinci bağımsız değişkene false aktaralım
var_dump(iterator_to_array(gen()));
?>
Yukarıdaki örneğin çıktısı:
array(3) { [0]=> int(1) [1]=> int(4) [2]=> int(3) }
Örnek 6 - yield from için temel kullanım
<?php
function count_to_ten() {
yield 1;
yield 2;
yield from [3, 4];
yield from new ArrayIterator([5, 6]);
yield from seven_eight();
yield 9;
yield 10;
}
function seven_eight() {
yield 7;
yield from eight();
}
function eight() {
yield 8;
}
foreach (count_to_ten() as $num) {
echo "$num ";
}
?>
Yukarıdaki örneğin çıktısı:
1 2 3 4 5 6 7 8 9 10
Örnek 7 - yield from ve dönen değerler
<?php
function count_to_ten() {
yield 1;
yield 2;
yield from [3, 4];
yield from new ArrayIterator([5, 6]);
yield from seven_eight();
return yield from nine_ten();
}
function seven_eight() {
yield 7;
yield from eight();
}
function eight() {
yield 8;
}
function nine_ten() {
yield 9;
return 10;
}
$gen = count_to_ten();
foreach ($gen as $num) {
echo "$num ";
}
echo $gen->getReturn();
?>
Yukarıdaki örneğin çıktısı:
1 2 3 4 5 6 7 8 9 10