forget about loops
TRANSCRIPT
![Page 1: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/1.jpg)
FORGET ABOUT LOOPSDUŠAN KASAN
![Page 3: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/3.jpg)
FORGET ABOUT LOOPSDUŠAN KASAN
What it’ll be about• The problem
• Functional programming
• Collection pipelines
• Collection pipelines in PHP
Problem | FP | Collection Pipelines | PHP
![Page 4: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/4.jpg)
What’s the problem?$output .= "function {$properties['unifunc']} (Smarty_Internal_Template \$_smarty_tpl) {\n"; // include code for pluginsif (!$cache) { if (!empty($_template->compiled->required_plugins[ 'compiled' ])) { foreach ($_template->compiled->required_plugins[ 'compiled' ] as $tmp) { foreach ($tmp as $data) { $file = addslashes($data[ 'file' ]); if (is_array($data[ 'function' ])) { $output .= "if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) require_once '{$file}';\n"; } else { $output .= "if (!is_callable('{$data['function']}')) require_once '{$file}';\n"; } } } } if ($_template->caching && !empty($_template->compiled->required_plugins[ 'nocache' ])) { $_template->compiled->has_nocache_code = TRUE; $output .= "echo '/*%%SmartyNocache:{$_template->compiled->nocache_hash}%%*/<?php \$_smarty = \$_smarty_tpl->smarty; "; foreach ($_template->compiled->required_plugins[ 'nocache' ] as $tmp) { foreach ($tmp as $data) { $file = addslashes($data[ 'file' ]); if (is_array($data[ 'function' ])) { $output .= addslashes("if (!is_callable(array('{$data['function'][0]}','{$data['function'][1]}'))) require_once '{$file}';\n"); } else { $output .= addslashes("if (!is_callable('{$data['function']}')) require_once '{$file}';\n"); } } } $output .= "?>/*/%%SmartyNocache:{$_template->compiled->nocache_hash}%%*/';\n"; }}
smarty_internal_runtime_codeframe.php
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 5: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/5.jpg)
Let’s boil it down[ { "id": 1, "username": "john", "verified": true, "posts": [ { "body": "Hi I'm John.", "likes": [2, 3, 5] }, { "body": "I hate this site.", "likes": [] } ] }, { "id": 2, "username": "tom", "verified": false, "posts": [] }, { "id": 3, "username": "jane", "verified": true, "posts": [ { "body": "Hi I'm Jane.", "likes": [4, 5] } ] }]
{ "1": [ { "body": "Hi I'm John.", "likes": [2, 3, 5] } ], "3": [ { "body": "Hi I'm jane.", "likes": [4, 5] } ]}
=>
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 6: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/6.jpg)
Let’s boil it down$likedPosts = [];foreach ($users as $user) { if ($user['verified']) { $userId = $user['id']; foreach ($user['posts'] as $post) { if (count($post['likes'])) { $likedPosts[$userId][] = $post; } } }}
4 levels of nesting
Harder to follow / cognitive load
Too much memorization
Refactoring candidate
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 7: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/7.jpg)
Refactoring - extract more functions$likedPosts = [];foreach ($users as $user) { if ($user['verified']) { $userId = $user['id']; foreach ($user['posts'] as $post) { if (count($post['likes'])) { $likedPosts[$userId][] = $post; } } }} private function getLikedPosts(array $posts)
{ $likedPosts = []; foreach ($posts as $post) { if (count($post['likes'])) { $likedPosts[] = $post; } } return $likedPosts; }
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 8: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/8.jpg)
Refactoring - extract more functions$likedPosts = [];foreach ($users as $user) { $likedPosts = $this->getLikedPosts($user['posts']); if ($user['verified'] && count($likedPosts)) { $likedPosts[$user['id']] = $likedPosts; }}
• Pretty good solution
• The new function name carries the meaning of the logic
• Enough for quick understanding
• For real understanding, we’ll hop between functions
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 9: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/9.jpg)
Refactoring - built-in array functions$indexedUsers = [];foreach ($users as $user) { $indexedUsers[$user['id']] = $user; }$verifiedUsers = array_filter( $indexedUsers, function ($user) { return $user['verified']; });
$likedPosts = array_map( function($verifiedUser) { return array_filter( $verifiedUser['posts'], function($post) {return count($post['likes']);} ); }, $verifiedUsers);
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 10: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/10.jpg)
Refactoring - built-in array functions
( °□°) ︵
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 11: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/11.jpg)
Refactoring - built-in array functions$indexedUsers = [];foreach ($users as $user) { $indexedUsers[$user['id']] = $user; }$verifiedUsers = array_filter( $indexedUsers, function ($user) { return $user['verified']; });
$likedPosts = array_map( function($verifiedUser) { return array_filter( $verifiedUser['posts'], function($post) {return count($post['likes']);} ); }, $verifiedUsers);
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 12: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/12.jpg)
Functional programming
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 13: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/13.jpg)
Functional programming buzzwords
Immutability
No side effects
Higher-order functions
Concurrency Parallelism
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 14: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/14.jpg)
Functional programming buzzwords
Immutability function withName(User $user, $name) { $result = User::from($user); $result->setName($name); return $result; } $tim = new User(1, ’tim', ....);$tom = withName($tim, 'tom'); echo $tim->getName(); //'tim'echo $tom->getName(); //'tom'
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
class User{ ... public function withName($name) { return new self($this->getId(), $name, ...); }}
![Page 15: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/15.jpg)
Functional programming buzzwords
Immutability
No side effects
Higher-order functions
Concurrency Parallelism
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 16: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/16.jpg)
Functional programming buzzwords
No side effects $anotherTry = function ($a, $b, $c) { return $a . $b . $c; }; $a = $anotherTry( $randomObscureThing, $_REQUEST['absolutely_safe'], DateTime::ATOM );
$totallyNoSideEffectsHere = function () use ($randomObscureThing) { return $randomObscureThing . $_REQUEST['absolutely_safe'] . DateTime::ATOM; }; $a = $totallyNoSideEffectsHere();
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 17: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/17.jpg)
Functional programming buzzwords
Immutability
No side effects
Higher-order functions
Concurrency Parallelism
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 18: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/18.jpg)
Functional programming buzzwords
Higher-order functions
function show(callable $c) { echo $c();} function style(callable $c) : callable { return function () use ($c) { return '**' . $c() . '**'; };} $nameProvider = function () { return 'John'; }; show($nameProvider); //Johnshow(style($nameProvider)); //**John**
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 19: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/19.jpg)
Functional programming buzzwords
Immutability
No side effects
Higher-order functions
Concurrency Parallelism
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 20: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/20.jpg)
Functional programming buzzwords
Concurrency Parallelism
getOrderDetails( getOrderById($id), getPaymentByOrderId($id) );
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 21: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/21.jpg)
Collection Pipelines ( - )
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 22: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/22.jpg)
Collection Pipelines• What are collections?
• Group of values or key, value pairs
• Think arrays or Traversables
• Collection pipeline
• Design pattern
• Sequential operations on collections
• Operations e.g.: filter, map or reduce
• Used by both FP and OOP languages
• Immutable, lazy, concurrent
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 23: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/23.jpg)
Simple explanation
map([🌽, 🐮, 🐔], cook) => [🍿, 🍔, 🍳]
filter([🍿, 🍔, 🍳], isVegetarian) => [🍿, 🍳]
reduce([🍿, 🍳], eat) => 💩From a tweet by @steveluscher
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 24: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/24.jpg)
Simple explanation
[🌽, 🐮, 🐔]
.map(cook) // [🍿, 🍔, 🍳]
.filter(isVegetarian) // [🍿, 🍳]
.reduce(eat) // 💩
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 25: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/25.jpg)
Collection pipeline operations
append, combine, concat, contains, countBy, cycle, diff, distinct,
drop, dropLast, dropWhile, each, every, except, extract, filter, find,
first, flatten, flip, frequencies, get, getOrDefault, groupBy,
groupByKey, has, indexBy, interleave, interpose, intersect, isEmpty,
isNotEmpty, keys, last, map, mapcat, only, partition, partitionBy,
prepend, realize, reduce, reduceRight, reductions, reject, replace,
reverse, second, shuffle, size, slice, some, sort, splitAt, splitWith,
take, takeNth, takeWhile, transform, toArray, zip,
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 26: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/26.jpg)
The original problem[ { "id": 1, "username": "john", "verified": true, "posts": [ { "body": "Hi I'm John.", "likes": [2, 3, 5] }, { "body": "I hate this site.", "likes": [] } ] }, { "id": 2, "username": "tom", "verified": false, "posts": [] }, { "id": 3, "username": "jane", "verified": true, "posts": [ { "body": "Hi I'm Jane.", "likes": [4, 5] } ] }]
{ "1": [ { "body": "Hi I'm John.", "likes": [2, 3, 5] } ], "3": [ { "body": "Hi I'm jane.", "likes": [4, 5] } ]}
=>
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 27: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/27.jpg)
Refactoring - Collections$likedPosts = [];foreach ($users as $user) { if ($user['verified']) { $userId = $user['id']; foreach ($user['posts'] as $post) { if (count($post['likes'])) { $likedPosts[$userId][] = $post; } } }}
$likedPosts = Collection::from($users) ->filter(function ($user) {return $user['verified'];}) ->indexBy(function($user) {return $user['id'];}) ->map(function($user) { return Collection::from($user['posts']) ->filter(function($post) {return count($post['likes']);}); }) ->reject(function($posts) {return isEmpty($posts);});
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 28: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/28.jpg)
When to use collection pipelines• Where you work with collections?
• API
• Import CSV
• Any nontrivial collection based work
• Refactoring of current code base to for comprehension
Drawbacks?• Function call overhead
• You have to understand it :)
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 29: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/29.jpg)
Collection pipelines in PHP• CakePHP Collection (github.com/cakephp/collection)
• Laravel Collections (github.com/illuminate/support)
• PHP-Collection (github.com/emonkak/php-collection)
• Knapsack (github.com/DusanKasan/Knapsack)
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 30: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/30.jpg)
PHP’s shortcomings
$collection->map(function($item) {return $item->field;});
$collection->map($item ~> $item->field);
$collection->map(function($item) { return $item->field; });
$collection->map(function($item) => $item->field);
RFC targeting PHP 7.1
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 31: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/31.jpg)
Interested?
• Martin Fowler (martinfowler.com)
• Adam Wathan (adamwathan.me/refactoring-to-collections)
• Documentation and tests to the mentioned libraries
FORGET ABOUT LOOPSDUŠAN KASAN Problem | FP | Collection Pipelines | PHP
![Page 32: Forget about loops](https://reader030.vdocument.in/reader030/viewer/2022020203/58f05b4d1a28ab666e8b4627/html5/thumbnails/32.jpg)
FORGET ABOUT LOOPSDUŠAN KASAN