Üreteçler Üreteçlere giriş Üreteçler, Iterator arayüzünü gerçekleyen bir sınıfı gerçeklemenin karmaşıklığı ve giderleri olmaksızın basit yineleyicileri gerçeklemek için kolay bir yol sağlar. Bir üreteç, önemli miktarda işlem süresi gerektirmeden ve bellek sınırını aşabilecek bir dizi oluşturmaya gerek kalmadan bir dizi veriyi yinelemek için &foreach; kullanan bir kod yazmanızı sağlar. Bunun için bir üreteç işlevini normal bir işlev yazar gibi yazabilirsiniz, siz bir kez değer döndürmeyi, beklerken bir üreteç üzerinde yinelenecek değerleri sağlamak için gerektiği kadar çok kez değer döndürebilir. Buna basit bir örnek range işlevini bir üreteç olarak tekrar gerçeklemektir. Standard range işlevi her değeri ve onun dönen değerini içeren devasa boyutlara ulaşabilen bir dizi üretmek zorundadır. Örneğin, range(0, 1000000) çağrısı 100MB üzerinde bellek kullanımıyla sonuçlanabilir. Bir seçenek olarak, bir xrange() üreteci gerçekleyebiliriz, tek ihtiyacımız bir Iterator nesnesi oluşturmaya yetecek bellek ayırmak ve 1 kilobayttan azıyla dönmesi için üretecin dahili durumunu izlemektir. - <function>range</function> işlevini bir üreteç olarak gerçeklemek = 0) { throw new LogicException('Step must be negative'); } for ($i = $start; $i >= $limit; $i += $step) { yield $i; } } } /* * range() ve xrange() işlevlerinin ikisi de aşağıda * benzer çıktıyı verecektir. */ echo 'range() içindeki bir haneli tek sayılar: '; foreach (range(1, 9, 2) as $number) { echo "$number "; } echo "\n"; echo 'xrange() içindeki bir haneli tek sayılar: '; foreach (xrange(1, 9, 2) as $number) { echo "$number "; } ?> ]]> &example.outputs; <classname>Generator</classname> nesneleri Bir üreteç işlevi çağrıldığında dahili Generator sınıfının yeni bir nesnesi döner. Bu nesne Iterator arayüzünü gerçekler. Bu, sadece ileri doğru yineleme yapan bir yineleme nesnesinin yaptığını yapacak ve değer gönderme ve döndürme dahil, üretecin durumunu da değiştirmeye yarayacak çağırılabilir yöntemler sağlayacaktır. Generator sözdizimi 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 geri döner ve adeta bir dizi değerlerini tüketmiş gibi kod çağrılmaya devam eder. Bir üreteç değer döndürebilir ve Generator::getReturn kullanılarak alınabilir. <command>yield</command> sözcüğü Ü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. - Basit bir yield örneği ]]> &example.outputs; Dahili olarak, ilişkisel olmayan dizilerdeki gibi sıralı tamsayı anahtarlar üretilen (yield) değerlerle çiftler oluşturur. Değerleri anahtarlarla üretmek 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. - Bir anahtar/değer çifti üretimi $fields; } } foreach (input_parser($input) as $id => $fields) { echo "$id:\n"; echo " $fields[0]\n"; echo " $fields[1]\n"; } ?> ]]> &example.outputs; null değerlerin üretini Yield deyimini bağımsız değişkensiz kullanmak &null; değerinin otomatik bir anahtarla birlikte üretilmesini sağlar. - &null; üretmek ]]> &example.outputs; NULL [1]=> NULL [2]=> NULL } ]]> Başvuruya göre üretim Ü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: - Değerleri başvuruya göre üretmek 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).'... '; } ?> ]]> &example.outputs; <command>yield from</command> üzerinden üreteç ihalesi Ü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. Bir dizide saklama (örn, <function>iterator_to_array</function> ile) 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. - <function>iterator_to_array</function> ile <command>yield from</command> ]]> &example.outputs; int(1) [1]=> int(4) [2]=> int(3) } ]]> - <command>yield from</command> için temel kullanım ]]> &example.outputs; - <command>yield from</command> ve dönen değerler getReturn(); ?> ]]> &example.outputs; Üreteçlerin <classname>Iterator</classname> nesneleriyle karşılaştırılması Üreteçlerin başlıca getirisi basitlikleridir. Iterator sınıfının gerçeklenmesine kıyasla çok daha az kod yazılır ve kod genelde çok daha okunabilirdir. Örneğin aşağıdaki işlev ve sınıf eşdeğerdir: fileHandle = fopen($fileName, 'r')) { throw new RuntimeException('Couldn\'t open file "' . $fileName . '"'); } } public function rewind() { fseek($this->fileHandle, 0); $this->line = fgets($this->fileHandle); $this->i = 0; } public function valid() { return false !== $this->line; } public function current() { return $this->line; } public function key() { return $this->i; } public function next() { if (false !== $this->line) { $this->line = fgets($this->fileHandle); $this->i++; } } public function __destruct() { fclose($this->fileHandle); } } ?> ]]> Bu esnekliğin bir bedeli vardır, üreteçler sadece ileri sayan yineleyiciler olduklarından yineleme bir kere başladı mı bir daha başa sarılamazlar. Bunun bir diğer anlamı, aynı üretecin tekrar tekrar kullanılamamasıdır; üreteç işlevi tekrar çağrılarak üretecin yeniden oluşturulması gerekir. &reftitle.seealso; Nesne Yineleme