141
Witek Adamus PHPCon 2016, Rawa Mazowiecka

PHPCon 2016: PHP7 by Witek Adamus / XSolve

Embed Size (px)

Citation preview

Page 1: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Witek Adamus

PHPCon 2016, Rawa Mazowiecka

Page 2: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Why async and functional programming in PHP7 suck and how to get over it?

Page 3: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Who am I?

Page 4: PHPCon 2016: PHP7 by Witek Adamus / XSolve

5 years of

imperative

programming

2 years of

functional

programming

Back to

PHP7

Page 5: PHPCon 2016: PHP7 by Witek Adamus / XSolve

❏ What can functional programming bring to the table?

❏ When language can be described as functional?

Table of content

Page 6: PHPCon 2016: PHP7 by Witek Adamus / XSolve

❏ DIY: cleaning ❏ Transparent parallelism❏ Parallelism vs Concurrency

❏ Parallel collections

Table of content

Page 7: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Pros and cons of functional programming

Pros Cons

Efficiency Efficiency

Entry threshold Entry threshold

Mathematical description of

reality

Mathematical description of

reality

Page 8: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Pros and cons of functional programming

Pros Cons In result

Efficiency Efficiency Scalability

Entry threshold Entry threshold Let’s get the party started

Mathematical description of

reality

Mathematical description of

reality

Shorter and more descriptive code

Page 9: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function someMethodWithMisleadingName( array $mysteriousInput){ $arr = []; foreach ($mysteriousInput as $inp) { if ($inp > 10) { $arr[] = $inp; } } $arrLeft = $arrRight = $arrCenter = []; foreach ($arr as $elem) { $bucket = $elem <=> 20; if ($bucket < 0) { $arrLeft[] = $elem; } if ($bucket == 0) { $arrCenter[] = $elem; } if ($bucket > 0) { $arrRight[] = $elem;} } $countLeft = count($arrLeft); $countCenter = count($arrCenter); $countRight = count($arrRight); return array_sum([$countLeft, $countCenter, $countRight]) / 3;}

Page 10: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function someMethodWithMisleadingName( array $mysteriousInput) { $arr = []; foreach ($mysteriousInput as $inp) { if ($inp > 10) { $arr[] = $inp; } }

$arrLeft = $arrRight = $arrCenter = []; foreach ($arr as $elem) { $bucket = $elem <=> 20; if ($bucket < 0) { $arrLeft[] = $elem; } if ($bucket == 0) { $arrCenter[] = $elem; } if ($bucket > 0) { $arrRight[] = $elem;} }

$countLeft = count($arrLeft); $countCenter = count($arrCenter); $countRight = count($arrRight);

return array_sum([$countLeft, $countCenter, $countRight]) / 3;}

public function someMethodWithMisleadingName( ParallelListCollection $mysteriousInput) { return $mysteriousInput ->filter(function ($elem) { return $elem > 10; }) ->partition(function ($elem) { return $elem <=> 20; }) ->map(function ($bucket) { return $bucket->count(); }) ->avg();}

Page 11: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function someMethodWithMisleadingName( array $mysteriousInput) { $arr = []; foreach ($mysteriousInput as $inp) { if ($inp > 10) { $arr[] = $inp; } }

$arrLeft = $arrRight = $arrCenter = []; foreach ($arr as $elem) { $bucket = $elem <=> 20; if ($bucket < 0) { $arrLeft[] = $elem; } if ($bucket == 0) { $arrCenter[] = $elem; } if ($bucket > 0) { $arrRight[] = $elem;} }

$countLeft = count($arrLeft); $countCenter = count($arrCenter); $countRight = count($arrRight);

return array_sum([$countLeft, $countCenter, $countRight]) / 3;}

public function someMethodWithMisleadingName( ParallelListCollection $mysteriousInput) { return $mysteriousInput ->filter(function ($elem) { return $elem > 10; }) ->partition(function ($elem) { return $elem <=> 20; }) ->map(function ($bucket) { return $bucket->count(); }) ->avg();}

Page 12: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Fundamental concepts in functional programming

❏ Function is a first-class citizen

❏ No side effects

❏ Immutability

❏ Lambda Calculus

Page 13: PHPCon 2016: PHP7 by Witek Adamus / XSolve

First-class citizen

❏ Can be stored in variable and data structures

❏ Can be passed as a parameter to procedure/functions

❏ Can be returned by procedures/functions

❏ Can be instantiated inline

❏ Has it’s own identity (name independent)

Page 14: PHPCon 2016: PHP7 by Witek Adamus / XSolve

No side effects? Immutability?

:(

Page 15: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Lambda Calculus

ƛ(x) = z

Page 16: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Lambda Calculus

ƛ(x) = z❏ Higher-order functions❏ Currying

Page 17: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Functional vs Object oriented programming

?

Page 18: PHPCon 2016: PHP7 by Witek Adamus / XSolve
Page 19: PHPCon 2016: PHP7 by Witek Adamus / XSolve

PHP7 is functional

…but is dirty and salty as well

Page 20: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 21: PHPCon 2016: PHP7 by Witek Adamus / XSolve

❏ Immutability by default❏ Objects cloning❏ Options❏ Either❏ Future❏ Parallel collections❏ Tail recurrency

❏ Generic types❏ Arrow functions❏ Pattern matching / case classes

Page 22: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Few rules to make your code functional

Page 23: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

❏ reassignments❏ if❏ null❏ for❏ foreach

Page 24: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

❏ reassignments

Page 25: PHPCon 2016: PHP7 by Witek Adamus / XSolve

$bigHouse = new Building(5);$smallerHouse = $bigHouse->setFloors(2);

echo $bigHouse->getFloors() . PHP_EOL; echo $smallerHouse->getFloors() . PHP_EOLl;

Page 26: PHPCon 2016: PHP7 by Witek Adamus / XSolve

$bigHouse = new Building(5);$smallerHouse = $bigHouse->setFloors(2);

echo $bigHouse->getFloors() . PHP_EOL; //2echo $smallerHouse->getFloors() . PHP_EOLl; //2

Page 27: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class Building{ protected $floors;

public function __construct(int $floors) { $this->setFloors($floors); }

public function getFloors() : int { return $this->floors; }

public function setFloors(int $floors) : Building { $this->floors = $floors; return $this; }}

Page 28: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class Building{ protected $floors;

public function __construct(int $floors) { $this->floors = $floors; }

public function getFloors() : int { return $this->floors; }

private function setFloors(int $floors) : Building { $this->floors = $floors; return $this; }

public function withFloors(int $floors) : Building { return (clone($this))->setFloors($floors); }}

Page 29: PHPCon 2016: PHP7 by Witek Adamus / XSolve

$bigHouse = new Building(5);$smallerHouse = $bigHouse->withFloors(2);

echo $bigHouse->getFloors() . PHP_EOL; //5echo $smallerHouse->getFloors() . PHP_EOLl; //2

Page 30: PHPCon 2016: PHP7 by Witek Adamus / XSolve

trait Copy{ public function copy($field, $value) { $clone = clone $this; $clone->$field = $value; return $clone; }}

Page 31: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Util\Copy;

class Building{ use Copy;

protected $floors;

public function __construct(int $floors) { $this->floors = $floors; }

public function getFloors() : int { return $this->floors; }

public function withFloors(int $floors) : Building { return $this->copy('floors', $floors); }}

Page 32: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Few rules to make your code functional

Page 33: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

:) reassignments❏ if❏ null❏ for❏ foreach

Page 34: PHPCon 2016: PHP7 by Witek Adamus / XSolve

https://github.com/php-slang/php-slang

Page 35: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

:) reassignments❏ if❏ null❏ for❏ foreach

?

Page 36: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

:) reassignments❏ if❏ null❏ for❏ foreach

Option

Page 37: PHPCon 2016: PHP7 by Witek Adamus / XSolve

OptionMonad which may contain something or nothing

Page 38: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What is a monad?Option

Page 39: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Fishy Monad Tutorial

http://maciejpirog.github.io/fishy/ (cc-by-sa)

Page 40: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Fishy Monad Tutorial

http://maciejpirog.github.io/fishy/ (cc-by-sa)

Page 41: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Fishy Monad Tutorial

http://maciejpirog.github.io/fishy/ (cc-by-sa)

Page 42: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Fishy Monad Tutorial

http://maciejpirog.github.io/fishy/ (cc-by-sa)

Page 43: PHPCon 2016: PHP7 by Witek Adamus / XSolve

https://github.com/php-slang/php-slang

# composer require php-slang/php-slang

Page 44: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Option

Option

NoneSome

Page 45: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Option

Option

NoneSomemap(Closure $expression)getOrElse($default)

map(Closure $expression)getOrElse($default)

Page 46: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Option

Option

NoneSomemap(Closure $expression)getOrElse($default)

map(Closure $expression)getOrElse($default)

Some($expression($this->content)

$this->content

Page 47: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Option

Option

NoneSomemap(Closure $expression)getOrElse($default)

map(Closure $expression)getOrElse($default)

None

$default

Page 48: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class UserRepository extends EntityRepository{ public function findByEmail(string $email) : User { $user = $this->findOneByMail(['email' => $email]);

if (!$user instanceof User) { throw new NotFoundException("oh my"); }

return $user; }}

public function findUserAction(string $email) : Response try { $user = $this ->userRepository ->findByEmail($email); return new Response($user); } catch (NotFoundException $exception) { return new Response([], Response::HTTP_NOT_FOUND); }}

Page 49: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class UserRepository extends EntityRepository{ public function findByEmail(string $email) : Option { return Option::of($this>findOneByMail(['email' => $email])); }}

public function findUserAction(string $email) : Response return $this ->userRepository ->findByEmail($email)); ->map(function (User $user) { return new Response($user); }) ->getOrElse(new Response('', Response::HTTP_NOT_FOUND));}

Page 50: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class UserRepository extends EntityRepository{ public function findByEmail(string $email) : User { $user = $this->findOneByMail(['email' => $email]);

if (!$user instanceof User) { throw new NotFoundException("oh my"); }

return $user; }}

public function findUserAction(string $email) : Response try { $user = $this ->userRepository ->findByEmail($email); return new Response($user); } catch (NotFoundException $exception) { return new Response([], Response::HTTP_NOT_FOUND); }}

class UserRepository extends EntityRepository{ public function findByEmail(string $email) : Option { return Option::of( $this>findOneByMail(['email' => $email])); }}

public function findUserAction(string $email) : Response return $this ->userRepository ->findByEmail($email)); ->map(function (User $user) { return new Response($user); }) ->getOrElse( new Response('', Response::HTTP_NOT_FOUND));}

Page 51: PHPCon 2016: PHP7 by Witek Adamus / XSolve

OptionHow about nesting

Page 52: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->get() ->getFirstName();}

Page 53: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->map(function (User $user) { return $user->firstName; }) ->getOrElse('oh my');}

Page 54: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : ???{ $this ->userRepository ->findByEmail($email) ->map(function (User $user) { return $user->getFirstName(); });}

Page 55: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : ???{ $this ->userRepository ->findByEmail($email) ->map(function (User $user) { return $user->getFirstName(); });}

?

Page 56: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : ???{ $this ->userRepository ->findByEmail($email) ->map(function (User $user) { return $user->getFirstName(); });}

Option<Option<String>>

Page 57: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : Option{ $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); });}

Page 58: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); }) ->getOrElse($email);}

Page 59: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); }) ->getOrCall(function () use ($email) { $this->getAlternative($email); });}

Page 60: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); }) ->getOrCall($this->getAlternative($email));}

Page 61: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); }) ->getOrCall($this->getAlternative($email));}

public function getAlternative(string $email) : \Closure{ return function () use (string $email) : string { return $this->doSomethingElseWith($email); };}

Page 62: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Few rules to make your code functional

Page 63: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

:) reassignments:) if:) null❏ for❏ foreach

Page 64: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Shortened notation for anonymous functions

Page 65: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ return $this ->userRepository ->findByEmail($email) ->flatMap(function (User $user) { return $user->getFirstName(); }) ->getOrCall($this->getAlternative($email));}

public function getAlternative(string $email) : \Closure{ return function () use (string $email) : string { return $this->doSomethingElseWith($email); };}

Page 66: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function displayNameForUser(string $email) : string{ $this ->userRepository ->findByEmail($email) ->flatMap((User $user) => $user->getFirstName()) ->getOrCall(() => $this->doSomethingElseWith($email))} :(

Page 67: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Generic types

Page 68: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function maybeSomething(string $email) : Option{ ...}

Page 69: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function maybeSomething(string $email) : Option<string>{ ...}

Page 70: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function maybeSomething(string $email) : Option<string>{ ...}

❏ Version: 0.4.0❏ Date: 2016-01-06❏ Author: Ben Scholzen 'DASPRiD' [email protected], Rasmus Schultz [email protected]❏ Status: Draft❏ First Published at: http://wiki.php.net/rfc/generics

:(

Page 71: PHPCon 2016: PHP7 by Witek Adamus / XSolve

/*** @return Option<string>*/public function maybeSomething(string $email) : Option{ ...}

https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc.md

:(

Page 72: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 73: PHPCon 2016: PHP7 by Witek Adamus / XSolve

:) Immutability by default:) Objects cloning:) Options❏ Either❏ Future❏ Parallel collections❏ Tail recurrency

:( Generic types:( Arrow functions❏ Pattern matching / case classes

Page 74: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Either

Page 75: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Either

Either

RightLeft

Page 76: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Either

Either

RightLeftleft(Closure $expr): Eitherright(Closure $expr): Eitherget()

left(Closure $expr): Eitherright(Closure $expr): Eitherget()

Page 77: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function findUserAction(string $email) : Response try { $user = $this ->userRepository ->findByEmail($email); return new Response($user); } catch (NotFoundException $exception) { return new Response([], Response::HTTP_NOT_FOUND); }}

Page 78: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function findUserAction(string $email) : Response try { $user = $this ->userRepository ->findByEmail($email); return new Response($user); } catch (NotFoundException $exception) { return new Response([], Response::HTTP_NOT_FOUND); } catch (ExternalServiceResponseException $exception) { return new Response([], Response::HTTP_FAILED_DEPENDENCY); } catch (IncorrectEmailException $exception) { return new Response([], Response::HTTP_BAD_REQUEST); } catch (UserNotAllowedException $exception) { return new Response([], Response::HTTP_FORBIDDEN); }}

“Co jest piękniejszego niż rdest? No chyba tylko bylina rdestu, bo rzadziej występuje.”Ohanhutep

Page 79: PHPCon 2016: PHP7 by Witek Adamus / XSolve

interface ServiceError {}

class NotFound implements ServiceError {}class ServiceNotWorking implements ServiceError {}class Param2IsPoorlyFormatted implements ServiceError {}

public function getSomethingNontrivial(string $param1, string $param2, string $param3) : Either{ ...}

Either<ServiceError, User>

Page 80: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function exampleAction(string $param1, string $param2, string $param3) : Response {

return $this ->userService ->getSomethingNontrivial($param1, $param2, $param3) ->left(function (ServiceError $someKindOfFailure) : Response { new Case(ServiceNotWorking::class, new Response('', Response::HTTP_FAILED_DEPENDENCY)), new Case(Param2IsPoorlyFormatted::class, new Response('', Response::HTTP_BAD_REQUEST)), new Case(NotFound()::class, new Response([], Response::HTTP_NOT_FOUND)); }) ->right(function (User $nonTrivialAllRight) : Response { return new Response($nonTrivialAllRight, Response::HTTP_OK); }) ->get();}

Page 81: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function getSomethingNontrivial( string $param1, string $param2, string $param3) : Either{ return $this ->translateParam2($param2) ->map(function ($param2Translated) { return new Right($this->getUserBy($param2Translated)); }) ->getOrElse(new Left(new Param2IsPoorlyFormatted()));}

Page 82: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function getSomethingNontrivial(string $param1, string $param2, string $param3) : Either{ return $this ->translateParam2($param2) ->map($this->handleWithTranslatedParam($param1, $param3)) ->getOrElse(new Left(new Param2IsPoorlyFormatted()));}

public function handleWithTranslatedParam(string $param1, string $param3) : \Clojure{ return function (Param2Translated $param2Translated) use ($param1, $param3) : Either { return $this ->someOtherMagic($param2Translated, $param1, $param3) ->map(function (User $magicResult) use ($param1, $param3) : Either { return new Right($magicResult); }) ->getOrElse(new Left(new ServiceNotWorking())); };}

Page 83: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 84: PHPCon 2016: PHP7 by Witek Adamus / XSolve

:) Immutability by default:) Objects cloning:) Options❏ Either❏ Future❏ Parallel collections❏ Tail recurrency

:( Generic types:( Arrow functions❏ Pattern matching / case classes

Page 85: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Pattern Matching

Page 86: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function exampleAction(string $param1, string $param2, string $param3) : Response{ return $this ->userService ->getSomethingNontrivial($param1, $param2, $param3) ->left(function (ServiceError $someKindOfFailure) : Response { return (Match::of($someKindOfFailure))->match( new Case(ServiceNotWorking::class, new Response('', Response::HTTP_FAILED_DEPENDENCY)), new Case(Param2IsPoorlyFormatted::class, new Response('', Response::HTTP_BAD_REQUEST)), new Case(NotFound::class, new Response([], Response::HTTP_NOT_FOUND)); }) ->right(function (User $nonTrivialAllRight) : Response { return new Response($nonTrivialAllRight, Response::HTTP_OK); }) ->get();}

Page 87: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def update(id: String): Action[JsValue] = Action.async(parse.json) { request => user.update(id, userConverterFactory.of(request.body).toInput)

.map {case Right(user) => Ok(user)case Left(UserService.UserNotFound) => NotFoundcase Left(UserService.VersioningMissmatch) => NotAcceptablecase Left(UserService.NoModificationsAllowed) => Lockedcase Left(UserService.InvalidPayload) => BadRequest

}}

Page 88: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 89: PHPCon 2016: PHP7 by Witek Adamus / XSolve

:) Immutability by default:) Objects cloning:) Options:) Either❏ Future❏ Parallel collections❏ Tail recurrency

:( Generic types:( Arrow functions:)/:( Pattern matching / case classes

Page 90: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Parallel collections

Page 91: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function multiplyBy( array $input, float $multiplication): array{ $output = [];

foreach($input as $number) { $output[] = $number * $multiplication; }

return $output;}

Page 92: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ListCollection;...public function beautifulMultiplyBy( array $input, float $multiplication) : ListCollection{ return (new ListCollection($input)) ->map(function ($number) use ($multiplication) { return $number * $multiplication; });}

Page 93: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function multiplyOddsBy( array $input, float $multiplication): array{ $output = [];

foreach ($input as $number) { if ($number % 2 !== 0) { $output[] = $number * $multiplication; } }

return $output;}

Page 94: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function beautifulMultiplyOddsBy( array $input, float $multiplication) : ListCollection{ return (new ListCollection($input)) ->filter(function ($number) { return $number % 2 !== 0; }) ->map(function ($number) use ($multiplication) { return $number * $multiplication; });}

Page 95: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function accumulatedText(array $words) : string { $text = '';

foreach ($words as $word) { $text .= $word . ' '; }

return $text;}

Page 96: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function accumulatedText(array $words) : string{ return (new ListCollection($words)) ->fold('', function (string $acumulator, string $word) { return $acumulator . $word . ' '; });}

Page 97: PHPCon 2016: PHP7 by Witek Adamus / XSolve
Page 98: PHPCon 2016: PHP7 by Witek Adamus / XSolve

(new ListCollection([1,2,3,4]))->tail(); //ArrayCollection([2,3,4])

Page 99: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Few rules to make your code functional

Page 100: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Do not use

:) reassignments:) if:) null:) for:) foreach

Page 101: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Parallelism vs Concurrency

Page 102: PHPCon 2016: PHP7 by Witek Adamus / XSolve
Page 103: PHPCon 2016: PHP7 by Witek Adamus / XSolve
Page 104: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Future

Page 105: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1) : Response{ return $this ->nonBlockingService ->nonBlockingGet($id) ->map(function (NonBlockingGetResult $output) { return new Response($output); }) ->await();}

Page 106: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1) : Response{ return $this ->nonBlockingService ->nonBlockingGet($id) ->map(function (NonBlockingGetResult $output) { return new Response($output); }) ->await();}

Future<NonBlockingGetResult>

Jak powinno to wyglądać?

Page 107: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1) : Response{ return $this ->nonBlockingService ->nonBlockingGet($id) ->map(function (NonBlockingGetResult $output) { return new Response($output); }) ->await();}

Future<NonBlockingGetResult>

Jak powinno to wyglądać?

Future<Response>

Page 108: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1) : Response{ return $this ->nonBlockingService ->nonBlockingGet($id) ->map(function (NonBlockingGetResult $output) { return new Response($output); }) ->await();}

Future<NonBlockingGetResult>

Jak powinno to wyglądać?

Future<Response>

Response

Page 109: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1, string $id2, string $id3) : Response{ return Future::all([ $this->nonBlockingService1->nonBlockingGet($id1), $this->nonBlockingService2->nonBlockingGet($id2), $this->nonBlockingService3->nonBlockingGet($id3), ]) ->map(function ($output) { return new Response($output); }) ->await();}

Jak powinno to wyglądać?

Page 110: PHPCon 2016: PHP7 by Witek Adamus / XSolve

public function nonBlockingGet(string $id): Future{ ...}

public function exampleAction(string $id1, string $id2, string $id3) : Response{ return Future::all([ $this->nonBlockingService1->nonBlockingGet($id1), $this->nonBlockingService2->nonBlockingGet($id2), $this->nonBlockingService3->nonBlockingGet($id3), ]) ->map(function ($output) { return new Response($output); }) ->await();}

Jak powinno to wyglądać?

Page 111: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Future & Parallel collections

Page 112: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ListCollection;...public function beautifulMultiplyBy( array $input, float $multiplication) : ListCollection{ return (new ListCollection($input)) ->map(function ($number) use ($multiplication) { return $number * $multiplication; });}

Page 113: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ParallelListCollection;...public function beautifulMultiplyBy( array $input, float $multiplication) : ParallelListCollection{ return (new ParallelListCollection($input)) ->map(function ($number) use ($multiplication) { return $number * $multiplication; });}

Page 114: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class ParallelListCollection extends ListCollection{ public function map(Closure $func) { return Future::all( (new ArrayCollection($this->elements)) ->map(function ($element) use ($func) { return new Future(function () use ($func, $element) { return $func($element); }); }) ->toArray()) ->await(); }}

Page 115: PHPCon 2016: PHP7 by Witek Adamus / XSolve

class ParallelListCollection extends ListCollection{ public function map(\Closure $func) { return Future::all( (new ArrayCollection($this->elements)) ->map(function ($element) use ($func) { return new Future(function () use ($func, $element) { return $func($element); }); }) ->toArray()) ->await(); }}

ArrayCollection<Future<mixed>>

Future<ArrayCollection<mixed>>

ArrayCollection<mixed>

Page 116: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ParallelListCollection;...public function asyncChainedComputationExample(array $input) : ParallelListCollection{ return (new ParallelListCollection($input))

->map($this->transformationOne())

->map($this->transformationTwo())

->map($this->transformationThree();}

Page 117: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ParallelListCollection;...public function asyncChainedComputationExample(array $input) : ParallelListCollection{ return (new ParallelListCollection($input))

->map($this->transformationOne())

->map($this->transformationTwo())

->map($this->transformationThree();}

Page 118: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ParallelListCollection;...public function asyncChainedComputationExample(array $input) : ParallelListCollection{ return (new ParallelListCollection($input)) ->map(function ($number) { return Option::of($number) ->map($this->transformationOne())

->map($this->transformationTwo())

->map($this->transformationThree()

->get(); });}

Page 119: PHPCon 2016: PHP7 by Witek Adamus / XSolve

use PhpSlang\Collection\ParallelListCollection;…public function asyncChainedComputationExample(array $input) : ParallelListCollection{ return (new ParallelListCollection($input)) ->map(function ($number) { return Option::of($number) ->map($this->transformationOne())

->map($this->transformationTwo())

->map($this->transformationThree()

->get(); });}

Page 120: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 121: PHPCon 2016: PHP7 by Witek Adamus / XSolve

:) Immutability by default:) Objects cloning:) Options:) Either:)/:( Future:) Parallel collections❏ Tail recurrency

:( Generic types:( Arrow functions:)/:( Pattern matching / case classes

Page 122: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Tail recurrency

Page 123: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def fibonacci(index : Int) : Int = index match { case 0 | 1 => index case _ => fibonacci(index - 1 ) + fibonacci(index - 2)}

function fibonacci(int $index) : int{ return in_array($index, [0, 1]) ? $index : fibonacci($index - 1) + fibonacci($index - 2);}

Page 124: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def fibonacci(index : Int) : Int = index match { case 0 | 1 => index case _ => fibonacci(index - 1 ) + fibonacci(index - 2)}

function fibonacci(int $index) : int{ return in_array($index, [0, 1]) ? $index : fibonacci($index - 1) + fibonacci($index - 2);}

echo fibonacci(123123123123);

Fatal error: Maximum function nesting level of '...' reached, aborting!

Page 125: PHPCon 2016: PHP7 by Witek Adamus / XSolve

ini_set('xdebug.max_nesting_level', 9999999);

?

Page 126: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def fibonacci(index: Int): Int = { var a = 0 var b = 1 var i = 0

while (i < index) { val c = a + b a = b b = c i = i + 1 } return a}

function fibonacci(int $index) : int{ $a = 0; $b = 1; $i = 0;

while ($i < $index) { $c = $a + $b; $a = $b; $b = $c; $i += 1; } return $a;}

Page 127: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def recursiveFibonacci(n: Int, a:Int, b:Int): Int =n match { case 0 => a case _ => recursiveFibonacci( n-1, b, a+b ) }

def fibonacci( n : Int) : Int = recursiveFibonacci( n, 0, 1)

function recursiveFibonacci(int $n, int $a, int $b) { return ($n == 0) ? $a : recursiveFibonacci($n - 1, $b, $a + $b);}

function fibonacci(int $n) : int{ return recursiveFibonacci($n, 0, 1);}

Page 128: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def fibonacci(index : Int) : Int = index match { case 0 | 1 => index case _ => fibonacci(index - 1 ) + fibonacci(index - 2)}

function fibonacci(int $index) : int{ return in_array($index, [0, 1]) ? $index : fibonacci($index - 1) + fibonacci($index - 2);}

Page 129: PHPCon 2016: PHP7 by Witek Adamus / XSolve

def recursiveFibonacci(n: Int, a:Int, b:Int): Int =n match { case 0 => a case _ => recursiveFibonacci( n-1, b, a+b ) }

def fibonacci( n : Int) : Int = recursiveFibonacci( n, 0, 1)

function recursiveFibonacci(int $n, int $a, int $b) { return ($n == 0) ? $a : recursiveFibonacci($n - 1, $b, $a + $b);}

function fibonacci(int $n) : int{ return recursiveFibonacci($n, 0, 1);} :(

Page 130: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Tail recurrencyTrampolines

Page 131: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Recurrency

Page 132: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Recurrency Trampoline

Page 133: PHPCon 2016: PHP7 by Witek Adamus / XSolve

<?php

namespace PhpSlang\Util\Trampoline;...class Trampoline{ /** * @var TrampolineResult */ var $expression;

public function __construct(Closure $expression) { $this->expression; } public function run() { $result = new Bounce(function () { return ($this->expression)(); }); while ($result instanceof Bounce) { $result = $result->run(); } return $result->run()->get(); }}

interface TrampolineResult{ public function run() : TrampolineResult;

public function get();}

class Bounce implements TrampolineResult {...}

class Done implements TrampolineResult {...}

Page 134: PHPCon 2016: PHP7 by Witek Adamus / XSolve

function recursiveFibonacci(int $n, int $a, int $b) { return ($n == 0) ? $a : recursiveFibonacci($n - 1, $b, $a + $b);}

function fibonacci($n){ return recursiveFibonacci($n, 0, 1);}

echo fibonacci(8);

Page 135: PHPCon 2016: PHP7 by Witek Adamus / XSolve

function recursiveFibonacci(int $n, int $a, int $b) { return ($n == 0) ? new Done($a) : new Bounce(function () use ($n, $b, $a) { return recursiveFibonacci($n - 1, $b, $a + $b); });}

function fibonacci($n){ return (new Trampoline(function () use ($n) { return recursiveFibonacci($n, 0, 1); }))->run();}

echo fibonacci(8);

Page 136: PHPCon 2016: PHP7 by Witek Adamus / XSolve

What do I miss in PHP7 that Scala luckily has?

Page 137: PHPCon 2016: PHP7 by Witek Adamus / XSolve

:) Immutability by default:) Objects cloning:) Options:) Either:)/:( Future:) Parallel collections:) Tail recurrency

:( Generic types:( Arrow functions:)/:( Pattern matching / case classes

Page 138: PHPCon 2016: PHP7 by Witek Adamus / XSolve
Page 139: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Conclusions

● Don’t be afraid of monads● Don’t set traps for your team

● Learn Haskell, Clojure, Scala, F#, JavaScript -> TypeScript

Page 140: PHPCon 2016: PHP7 by Witek Adamus / XSolve

Witek Adamus

[email protected]

Page 141: PHPCon 2016: PHP7 by Witek Adamus / XSolve

xsolve.pl/nobodyexpects