SlideShare a Scribd company logo
Iterators & Generators
Practical Uses in Memory Management
Reach out
● Software Engineer
● Systems Administrator
● All around nerd
@aramonc
Memory Management in PHP
● Garbage collected
○ Reference counts
○ Happens after variable is unset, leave function
scope, or script ends, GC buffer is full
● All values are stored in hash tables of ZVAL structs
● Arrays are dynamically allocated by doubling the
size
● Much better in PHP 7 than 5.6
What are Iterators and Generators
Iterators are:
● An object that can be iterated over using a loop
● PHP has several built in the SPL
● Can create additional ones
● Special ones are the recursive & filter iterators
Generators are:
● A special kind of custom iterator
● Keywords & interfaces that allow you to define an
Iterator without having to create a class that
implements the interface
https://github.com/aramonc/ig_talk
Generating many values: The object
<?php
namespace ArcIgTalk;
class User
{
public $_id;
public $firstName;
public $lastName;
public $email;
public $password;
public $phoneNumber;
}
Generating many values: Generate some values
<?php
...
for ($i = 0; $i < 1000000; $i++) {
$user = new User();
$user->_id = new ObjectID();
$user->email = $faker->email;
$user->password = $faker->password(12, 32);
$user->firstName = $faker->firstName();
$user->lastName = $faker->lastName;
$user->phoneNumber = $faker->phoneNumber;
$users[] = $user;
if ($i % 5000 === 0) {
$collection->insertMany($users);
$users = [];
}
}
Generating many values: Generate some values
Processing values: Paginated Provider
<?php
namespace ArcIgTalk;
class Provider
{
public function getPagedList(int $page = 0, int $limit = 100): array
{
$cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]);
$users = [];
foreach ($cursor as $data) {
$users[] = $this->createUserEntity($data->getArrayCopy());
}
return $users;
}
}
Processing values: Paginated Provider
<?php
namespace ArcIgTalk;
class Provider
{
public function getPagedList(int $page = 0, int $limit = 100): array
{
$cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]);
$users = [];
foreach ($cursor as $data) {
$users[] = $this->createUserEntity($data->getArrayCopy());
}
return $users;
}
}
Processing values: Simple approach
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 10000; $up++) {
foreach ($provider->getPagedList($up) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Simple approach
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 10000; $up++) {
foreach ($provider->getPagedList($up) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Simple approach
Processing values: Why does it take so long?
● 3 nested loops
○ for ($up = 0; $up < 10000; $up++)
○ foreach ($provider->getPagedList($up) as $user)
○ foreach ($cursor as $data)
● O(n^3) or n*m*p
Processing values: What is going on?
<?php
namespace ArcIgTalk;
class Provider
{
public function getPagedList(int $page = 0, int $limit = 100): array
{
$cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]);
$users = [];
foreach ($cursor as $data) {
$users[] = $this->createUserEntity($data->getArrayCopy());
}
return $users;
}
}
Processing values: What is going on?
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 10000; $up++) {
foreach ($provider->getPagedList($up) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Make it faster
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 1000; $up++) {
foreach ($provider->getPagedList($up, 1000) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Make it faster
Processing values: What is going on?
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 1000; $up++) {
foreach ($provider->getPagedList($up, 1000) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Make it faster
<?php
$provider = new Provider(new Client("mongodb://datastore:27017"));
$emailLogPath = __DIR__ . '/../data/user.txt';
$emailLog = fopen($emailLogPath, 'w+');
for ($up = 0; $up < 100; $up++) {
foreach ($provider->getPagedList($up, 10000) as $user) {
fwrite($emailLog, $user->email . "n");
}
}
fclose($emailLog);
Processing values: Make it faster
Processing values: Make it better
<?php
namespace ArcIgTalk;
class Provider
{
public function getPagedList(int $page = 0, int $limit = 100): Generator
{
$cursor = $this->collection->find([],[ 'limit' => $limit,'skip' => $page * $limit]);
foreach ($cursor as $data) {
/** @var $data BSONDocument */
yield $this->createUserEntity($data->getArrayCopy());
}
}
}
Processing values: Make it better
Processing values: It’s a bit slower
● 3 nested loops
○ for ($up = 0; $up < 10000; $up++)
○ foreach ($provider->getPagedList($up) as $user)
○ foreach ($cursor as $data)
● Effectively only 2
● O(n^2) or n*m
● Extra time for YIELD to go back & forth
We can do more! Let’s filter the list!
Filter values: Abstract the pagination
<?php
namespace ArcIgTalk;
class Service
{
const LIMIT = 100000;
public function getList(int $limit): Generator
{
$pages = ceil($limit / self::LIMIT);
$innerLimit = $pages > 1 ? self::LIMIT : $limit;
for ($page = 0; $page < $pages; $page++) {
foreach ($this->provider->getPagedList($page, $innerLimit) as $user) {
yield $user;
}
}
}
}
Filter values: The filter
<?php
...
function filterGmailUsers(User $user): bool
{
$emailParts = explode('@', $user->email);
return $emailParts[1] === 'gmail.com';
}
$filtered = new CallbackFilterIterator(
$service->getList(1000000),
'filterGmailUsers'
);
foreach ($filtered as $user) {
fwrite($emailLog, $user->email . "n");
}
Filter values: The filter
http://bit.ly/2tgw6z7
Questions?

More Related Content

PDF
Introduzione JQuery
TXT
Exch test-mail flow
PDF
Desenvolvendo APIs usando Rails - Guru SC 2012
PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
RTF
ABV_fastcontact
PDF
Intoduction to php restful web service
ODP
The promise of asynchronous PHP
PDF
Perl web frameworks
Introduzione JQuery
Exch test-mail flow
Desenvolvendo APIs usando Rails - Guru SC 2012
Design Patterns avec PHP 5.3, Symfony et Pimple
ABV_fastcontact
Intoduction to php restful web service
The promise of asynchronous PHP
Perl web frameworks

What's hot (20)

PDF
Working with web_services
PPTX
Hacking hhvm
PDF
Connecting Content Silos: One CMS, Many Sites With The WordPress REST API
PDF
Javascript
PDF
Models and Service Layers, Hemoglobin and Hobgoblins
ZIP
Web Apps in Perl - HTTP 101
PDF
J querypractice
PDF
jQuery in 15 minutes
PDF
Jqeury ajax plugins
ODP
The promise of asynchronous php
PDF
PHP 5.3 and Lithium: the most rad php framework
PPTX
jQuery
PDF
Rails GUI Development with Ext JS
PDF
Developing applications for performance
PDF
Learning jQuery in 30 minutes
PDF
Eve - REST API for Humans™
PDF
Php summary
PDF
Play á la Rails
PPT
JQuery introduction
PPTX
jQuery from the very beginning
Working with web_services
Hacking hhvm
Connecting Content Silos: One CMS, Many Sites With The WordPress REST API
Javascript
Models and Service Layers, Hemoglobin and Hobgoblins
Web Apps in Perl - HTTP 101
J querypractice
jQuery in 15 minutes
Jqeury ajax plugins
The promise of asynchronous php
PHP 5.3 and Lithium: the most rad php framework
jQuery
Rails GUI Development with Ext JS
Developing applications for performance
Learning jQuery in 30 minutes
Eve - REST API for Humans™
Php summary
Play á la Rails
JQuery introduction
jQuery from the very beginning
Ad

Similar to Iterators & generators: practical uses in memory management (20)

PDF
Advanced Php - Macq Electronique 2010
PPTX
A Case Study of NoSQL Adoption: What Drove Wordnik Non-Relational?
KEY
NOSQL101, Or: How I Learned To Stop Worrying And Love The Mongo!
PDF
Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014
PPTX
Lessons Learned Migrating 2+ Billion Documents at Craigslist
PDF
Zend Server Data Caching
PDF
CMF: a pain in the F @ PHPDay 05-14-2011
PDF
Mongodb in-anger-boston-rb-2011
ODP
Intro to The PHP SPL
KEY
Mongo NYC PHP Development
PDF
2019 PHP Serbia - Boosting your performance with Blackfire
PDF
From SQL to MongoDB
KEY
Spl Not A Bridge Too Far phpNW09
PPTX
Benefits of Using MongoDB Over RDBMS (At An Evening with MongoDB Minneapolis ...
PPTX
Transitioning from SQL to MongoDB
PPTX
Reducing Development Time with MongoDB vs. SQL
ODP
Getting started with MongoDB and PHP
PPTX
Database Trends for Modern Applications: Why the Database You Choose Matters
PPTX
Mongo db tips and advance features
PPTX
Benefits of Using MongoDB Over RDBMSs
Advanced Php - Macq Electronique 2010
A Case Study of NoSQL Adoption: What Drove Wordnik Non-Relational?
NOSQL101, Or: How I Learned To Stop Worrying And Love The Mongo!
Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014
Lessons Learned Migrating 2+ Billion Documents at Craigslist
Zend Server Data Caching
CMF: a pain in the F @ PHPDay 05-14-2011
Mongodb in-anger-boston-rb-2011
Intro to The PHP SPL
Mongo NYC PHP Development
2019 PHP Serbia - Boosting your performance with Blackfire
From SQL to MongoDB
Spl Not A Bridge Too Far phpNW09
Benefits of Using MongoDB Over RDBMS (At An Evening with MongoDB Minneapolis ...
Transitioning from SQL to MongoDB
Reducing Development Time with MongoDB vs. SQL
Getting started with MongoDB and PHP
Database Trends for Modern Applications: Why the Database You Choose Matters
Mongo db tips and advance features
Benefits of Using MongoDB Over RDBMSs
Ad

More from Adrian Cardenas (7)

PPTX
Http/2 lightning
PPTX
PDF
Creating a phar
PDF
First there was the command line
PDF
Learning the command line
PDF
Conquering the Command Line
PDF
Communicating on the web
Http/2 lightning
Creating a phar
First there was the command line
Learning the command line
Conquering the Command Line
Communicating on the web

Recently uploaded (20)

PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Online Work Permit System for Fast Permit Processing
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
ai tools demonstartion for schools and inter college
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
Digital Strategies for Manufacturing Companies
PDF
top salesforce developer skills in 2025.pdf
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PPTX
history of c programming in notes for students .pptx
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PPTX
Odoo POS Development Services by CandidRoot Solutions
PPTX
Transform Your Business with a Software ERP System
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Nekopoi APK 2025 free lastest update
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Online Work Permit System for Fast Permit Processing
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
ai tools demonstartion for schools and inter college
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Digital Strategies for Manufacturing Companies
top salesforce developer skills in 2025.pdf
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Which alternative to Crystal Reports is best for small or large businesses.pdf
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
history of c programming in notes for students .pptx
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Odoo POS Development Services by CandidRoot Solutions
Transform Your Business with a Software ERP System
How Creative Agencies Leverage Project Management Software.pdf
Nekopoi APK 2025 free lastest update

Iterators & generators: practical uses in memory management

  • 1. Iterators & Generators Practical Uses in Memory Management
  • 2. Reach out ● Software Engineer ● Systems Administrator ● All around nerd @aramonc
  • 3. Memory Management in PHP ● Garbage collected ○ Reference counts ○ Happens after variable is unset, leave function scope, or script ends, GC buffer is full ● All values are stored in hash tables of ZVAL structs ● Arrays are dynamically allocated by doubling the size ● Much better in PHP 7 than 5.6
  • 4. What are Iterators and Generators Iterators are: ● An object that can be iterated over using a loop ● PHP has several built in the SPL ● Can create additional ones ● Special ones are the recursive & filter iterators Generators are: ● A special kind of custom iterator ● Keywords & interfaces that allow you to define an Iterator without having to create a class that implements the interface
  • 6. Generating many values: The object <?php namespace ArcIgTalk; class User { public $_id; public $firstName; public $lastName; public $email; public $password; public $phoneNumber; }
  • 7. Generating many values: Generate some values <?php ... for ($i = 0; $i < 1000000; $i++) { $user = new User(); $user->_id = new ObjectID(); $user->email = $faker->email; $user->password = $faker->password(12, 32); $user->firstName = $faker->firstName(); $user->lastName = $faker->lastName; $user->phoneNumber = $faker->phoneNumber; $users[] = $user; if ($i % 5000 === 0) { $collection->insertMany($users); $users = []; } }
  • 8. Generating many values: Generate some values
  • 9. Processing values: Paginated Provider <?php namespace ArcIgTalk; class Provider { public function getPagedList(int $page = 0, int $limit = 100): array { $cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]); $users = []; foreach ($cursor as $data) { $users[] = $this->createUserEntity($data->getArrayCopy()); } return $users; } }
  • 10. Processing values: Paginated Provider <?php namespace ArcIgTalk; class Provider { public function getPagedList(int $page = 0, int $limit = 100): array { $cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]); $users = []; foreach ($cursor as $data) { $users[] = $this->createUserEntity($data->getArrayCopy()); } return $users; } }
  • 11. Processing values: Simple approach <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 10000; $up++) { foreach ($provider->getPagedList($up) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 12. Processing values: Simple approach <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 10000; $up++) { foreach ($provider->getPagedList($up) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 14. Processing values: Why does it take so long? ● 3 nested loops ○ for ($up = 0; $up < 10000; $up++) ○ foreach ($provider->getPagedList($up) as $user) ○ foreach ($cursor as $data) ● O(n^3) or n*m*p
  • 15. Processing values: What is going on? <?php namespace ArcIgTalk; class Provider { public function getPagedList(int $page = 0, int $limit = 100): array { $cursor = $this->collection->find([],['limit' => $limit,'skip' => $page * $limit]); $users = []; foreach ($cursor as $data) { $users[] = $this->createUserEntity($data->getArrayCopy()); } return $users; } }
  • 16. Processing values: What is going on? <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 10000; $up++) { foreach ($provider->getPagedList($up) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 17. Processing values: Make it faster <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 1000; $up++) { foreach ($provider->getPagedList($up, 1000) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 19. Processing values: What is going on? <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 1000; $up++) { foreach ($provider->getPagedList($up, 1000) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 20. Processing values: Make it faster <?php $provider = new Provider(new Client("mongodb://datastore:27017")); $emailLogPath = __DIR__ . '/../data/user.txt'; $emailLog = fopen($emailLogPath, 'w+'); for ($up = 0; $up < 100; $up++) { foreach ($provider->getPagedList($up, 10000) as $user) { fwrite($emailLog, $user->email . "n"); } } fclose($emailLog);
  • 22. Processing values: Make it better <?php namespace ArcIgTalk; class Provider { public function getPagedList(int $page = 0, int $limit = 100): Generator { $cursor = $this->collection->find([],[ 'limit' => $limit,'skip' => $page * $limit]); foreach ($cursor as $data) { /** @var $data BSONDocument */ yield $this->createUserEntity($data->getArrayCopy()); } } }
  • 24. Processing values: It’s a bit slower ● 3 nested loops ○ for ($up = 0; $up < 10000; $up++) ○ foreach ($provider->getPagedList($up) as $user) ○ foreach ($cursor as $data) ● Effectively only 2 ● O(n^2) or n*m ● Extra time for YIELD to go back & forth
  • 25. We can do more! Let’s filter the list!
  • 26. Filter values: Abstract the pagination <?php namespace ArcIgTalk; class Service { const LIMIT = 100000; public function getList(int $limit): Generator { $pages = ceil($limit / self::LIMIT); $innerLimit = $pages > 1 ? self::LIMIT : $limit; for ($page = 0; $page < $pages; $page++) { foreach ($this->provider->getPagedList($page, $innerLimit) as $user) { yield $user; } } } }
  • 27. Filter values: The filter <?php ... function filterGmailUsers(User $user): bool { $emailParts = explode('@', $user->email); return $emailParts[1] === 'gmail.com'; } $filtered = new CallbackFilterIterator( $service->getList(1000000), 'filterGmailUsers' ); foreach ($filtered as $user) { fwrite($emailLog, $user->email . "n"); }