The Stateful ElePHPant

The Stateful ElePHPant

State machines and the state pattern seem to be pretty underestimated in the PHP world. Most examples found are of doors and other objects that have no application in most of our projects. Starting the talk I will be explaining what the state pattern is and how it's used in a game. Then we'll be discovering what this can do for us in the world of web applications. Following that we're taking a brief look at the state machine, how it's different from the pattern and why it's useful to us.

Instead of simply presenting you these concepts I prefer doing a live coding session so we can explore the possibilities together. You will be walking away from this talk with a solid understanding of the state pattern/state machine and the knowledge on when you should apply these concepts. There will also be plenty of time to have your questions answered.

At the end of the presentation I will also provide a list of useful resources that can help you introduce these concepts within your own projects.

C2cad13c5070e52586a683233588522e?s=128

Rick Kuipers

May 20, 2016
Tweet

Transcript

  1. THE STATEFUL ELEPHPANT RICK KUIPERS / @RSKUIPERS @PHPSTORMTIPS

  2. THE STATEFUL ELE ANT PHP C# RUBY PYTHON SCALA JAVA

    JAVASCRIPT GO PASCAL
  3. ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>+ +.>+.+++++++..+++.>++.<<+++++++++++++++.>.++ +.------.--------.>+.>. HAI 1.2 CAN HAS STDIO? VISIBLE "HAI

    WORLD!" KTHXBYE
  4. TOPICS ! STATE ! STATE DIAGRAM ! STATE MACHINES !

    STATE PATTERN
  5. STATE

  6. THE GAME

  7. STATE DIAGRAM

  8. ini#al state 10101 accep#ng state ✅ 01110 DETERMINISTIC FINITE AUTOMATON

    state transi#on ACCEPTOR
  9. DETERMINISTIC FINITE AUTOMATON TRANSDUCER MEALY

  10. DETERMINISTIC FINITE AUTOMATON TRANSDUCER MEALY

  11. FINITE STATE ACCEPTOR

  12. STATUSES PENDING NEW COMPLETED CANCELED REFUNDED

  13. DETERMINISTIC FINITE AUTOMATON ACCEPTOR

  14. $order = $this->getOrder(); $order->setStatus(Order::STATUS_COMPLETED);

  15. [ 'transitions' => [ 'create' => [ 'from' => ['new'],

    'to' => 'pending', ], 'cancel' => [ 'from' => ['new', 'pending'], 'to' => 'canceled', ], 'complete' => [ 'from' => ['pending'], 'to' => 'completed', ], 'refund' => [ 'from' => ['completed'], 'to' => 'refunded', ], ], ];
  16. $order = $this->getOrder(); $stateMachine = $stateMachineFactory->get($order); $stateMachine->apply('complete');

  17. $order = $this->getOrder(); $stateMachine = $stateMachineFactory->get($order); $stateMachine->apply('complete'); $stateMachine->apply('cancel'); PHP FATAL

    ERROR: UNCAUGHT SM\SMEXCEPTION: TRANSITION "CANCEL" CANNOT BE APPLIED ON STATE "COMPLETED" OF OBJECT "ORDER" WITH GRAPH "DEFAULT"
  18. Complete Refund Cancel $sm->can('cancel'); true $sm->can('refund'); false $sm->can('complete'); true

  19. Complete Refund Cancel $sm->can('cancel'); false $sm->can('refund'); true $sm->can('complete'); false

  20. Complete Refund Cancel $sm->can('cancel'); false $sm->can('refund'); false $sm->can('complete'); false

  21. [ 'callbacks' => [ 'after' => [ 'refund' => [

    ['Inventory\Callback\Refund', 'onRefund'], ], ], ], ];
  22. THE STATE PATTERN

  23. if (cursors.left.isDown) { player.body.velocity.x = -150; player.scale.x = 1; player.animations.play('left');

    if (player.body.touching.down) { state.text = 'running'; } } else if (cursors.right.isDown) { player.body.velocity.x = 150; player.scale.x = -1; player.animations.play('right'); if (player.body.touching.down) { state.text = 'running'; } } else { player.animations.stop(); player.frame = 2; if (player.body.touching.down) { state.text = 'idling'; } } if (game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR) && player.body.touching.down) { player.body.velocity.y = -350; state.text = 'jumping'; }
  24. THE GAME WITH STATE PATTERN

  25. var Elephpant = function(player) { this.state = new Idling(this, player);

    this.shoot = function() { // Shoot gigantic fireball }; this.transitionTo = function(state) { this.state = state; }; this.handle = function(input) { this.state.process(input); this.state.display(input); }; };
  26. var Idling = function(elephpant, player) { this.display = function() {

    player.body.velocity.x = 0; player.animations.stop(); player.frame = 2; }; this.process = function(input) { if (input.left.isDown || input.right.isDown) { elephpant.transitionTo(new Running(elephpant, player)); return; } if (input.up.isDown) { elephpant.transitionTo(new Jumping(elephpant, player)); return; } if (input.space.isDown) { elephpant.shoot(); } }; };
  27. var Jumping = function(elephpant, player) { this.display = function() {

    if (player.body.touching.down) { player.body.velocity.y = -350; } }; this.process = function(input) { if (!input.up.isDown && player.body.touching.down) { elephpant.transitionTo(new Idling(elephpant, player)); } }; };
  28. None
  29. THE STATE STRATEGY PATTERN?

  30. STRATEGY PATTERN ! Tries to achieve similar result for input

    ! Strategies can’t transition to other
 strategies ! Strategy processes the input and gives
 output to the caller STATE PATTERN ! Result can be completely different ! States can trigger transitions to other
 states ! State controls the behaviour of its
 wrapper
  31. WHY SHOULD WE CARE?

  32. CHECKOUT PAYMENT DETAILS REVIEW

  33. EXAMPLE

  34. None
  35. None
  36. RECAP FINITE STATE ACCEPTOR STATE PATTERN ! Monolith ! Acceptor

    (pa9ern matching) ! Is this a valid transi#on? ! Transi#ons are set in stone ! Callbacks are easy to implement ! Object Oriented ! Transducer (controlling) ! Different behaviour per state ! Reduces the amount of condi#onals
  37. PACKAGES DON’T REINVENT THE WHEEL ! https://github.com/winzou/state-machine ! https://github.com/Sylius/SyliusFlowBundle !

    https://github.com/rskuipers/stateful-elephpant ! https://github.com/rskuipers/stateful-elephpant-talk ! https://github.com/rskuipers/stateful-elephpant-expressive
  38. 4 @RSKUIPERS RICK KUIPERS QUESTIONS? RSKUIPERS@ENRISE.COM HTTPS://JOIND.IN/TALK/26C09