ExecutionLoopClosure.php 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <?php
  2. /*
  3. * This file is part of Psy Shell.
  4. *
  5. * (c) 2012-2023 Justin Hileman
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Psy;
  11. use Psy\Exception\BreakException;
  12. use Psy\Exception\ThrowUpException;
  13. /**
  14. * The Psy Shell's execution loop scope.
  15. *
  16. * @todo Switch ExecutionClosure to a generator and get rid of the duplicate closure implementations?
  17. */
  18. class ExecutionLoopClosure extends ExecutionClosure
  19. {
  20. /**
  21. * @param Shell $__psysh__
  22. */
  23. public function __construct(Shell $__psysh__)
  24. {
  25. $this->setClosure($__psysh__, function () use ($__psysh__) {
  26. // Restore execution scope variables
  27. \extract($__psysh__->getScopeVariables(false));
  28. while (true) {
  29. $__psysh__->beforeLoop();
  30. try {
  31. $__psysh__->getInput();
  32. try {
  33. // Pull in any new execution scope variables
  34. if ($__psysh__->getLastExecSuccess()) {
  35. \extract($__psysh__->getScopeVariablesDiff(\get_defined_vars()));
  36. }
  37. // Buffer stdout; we'll need it later
  38. \ob_start([$__psysh__, 'writeStdout'], 1);
  39. // Convert all errors to exceptions
  40. \set_error_handler([$__psysh__, 'handleError']);
  41. // Evaluate the current code buffer
  42. $_ = eval($__psysh__->onExecute($__psysh__->flushCode() ?: ExecutionClosure::NOOP_INPUT));
  43. } catch (\Throwable $_e) {
  44. // Clean up on our way out.
  45. if (\ob_get_level() > 0) {
  46. \ob_end_clean();
  47. }
  48. throw $_e;
  49. } finally {
  50. // Won't be needing this anymore
  51. \restore_error_handler();
  52. }
  53. // Flush stdout (write to shell output, plus save to magic variable)
  54. \ob_end_flush();
  55. // Save execution scope variables for next time
  56. $__psysh__->setScopeVariables(\get_defined_vars());
  57. $__psysh__->writeReturnValue($_);
  58. } catch (BreakException $_e) {
  59. $__psysh__->writeException($_e);
  60. return;
  61. } catch (ThrowUpException $_e) {
  62. $__psysh__->writeException($_e);
  63. throw $_e;
  64. } catch (\Throwable $_e) {
  65. $__psysh__->writeException($_e);
  66. }
  67. $__psysh__->afterLoop();
  68. }
  69. });
  70. }
  71. }