3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace Magnus; class ObjectDispatch { /* This version of object dispatch makes use of yield syntax which is only available from PHP 5.5 onwards. * If support for lower level versions are needed, another version of this dispatcher can be written to eliminate yield syntax. */ public function routeIterator(&$path) { while (!empty($path)) { yield end($path); array_pop($path); /* This prevents having to put back a value in the event of a * readjustment in the dispatch path. * Testing indicates that it's better to do array maninpulation than it is * to implement SplDoublyLinkedList for deque behavior. Likewise, * simply tracking the index is a bit slower and can add complexity * when dealing with reorients/redispatches. */ } } public function __invoke($context, $root) { $log = $context->getLogger(); $path = $context->getRequestPath(); $last = ''; $parent = null; $current = $root; $controllerPrefix = $context->getControllerPrefix(); if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('Starting Object Dispatch', [ 'request' => $context->getRequestURI(), 'path' => var_export($path, true), 'root' => var_export($root, true) ]); } foreach ($this->routeIterator($path) as $chunk) { if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('Beginning dispatch step.', [ 'chunk' => $chunk, 'path' => var_export($path, true), 'current' => var_export($current, true) ]); } if (!is_object($current) || class_exists($controllerPrefix . $current)) { if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('Instantiating current class', [ 'request' => $context->getRequestURI(), 'current' => $current ]); } $resolvedClass = $controllerPrefix . $current; $current = new $resolvedClass($context); } if (is_object($current)) { $parent = $current; } if (in_array($chunk, get_class_methods($parent))) { if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('Found an endpoint', [ 'request' => $context->getRequestURI(), 'isEndpoint' => true, 'parent' => var_export($parent, true), 'handler' => $chunk, 'arguments' => var_export($path, true) ]); } yield array($parent, $chunk, $path, true); } elseif (in_array($chunk, get_object_vars($parent))) { if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('Found a property', [ 'request' => $context->getRequestURI(), 'property' => $chunk, 'parent' => var_export($parent, true) ]); } $current = $parent->chunk; } elseif (method_exists($parent, 'lookup')) { try { list($current, $consumed) = $parent->lookup($path); $chunk = implode('/', $consumed); $path = array_slice($path, 0, count($path) - count($consumed)); } catch (Exception $e) { throw new HTTPNotFound(); } } else { throw new HTTPNotFound(); } yield array(explode('/', $last), $parent, false); $last = $chunk; } if ($context->getAppMode() === 'DEBUG' && $log !== null) { $log->addDebug('No endpoint found', [ 'request' => $context->getRequestURI(), 'current' => var_export($current), 'parent' => var_export($parent) ]); } if (!is_object($current) && class_exists($controllerPrefix . $current)) { $resolvedClass = $controllerPrefix . $current; $current = new $resolvedClass($context); } if (is_callable($current)) { yield array($current, $last, $path, true); } elseif (is_callable($parent)) { yield array($parent, $last, $path, true); } } } class Context { protected $requestURI; protected $requestPath; protected $appMode; protected $logger; protected $controllerPrefix; public function __construct(Array $config) { $this->requestURI = isset($config['requestURI']) ? $config['requestURI'] : '/'; $this->appMode = isset($config['appMode']) ? $config['appMode'] : 'DEVELOPMENT'; $this->logger = isset($config['logger']) ? $config['logger'] : null; $this->controllerPrefix = isset($config['controllerPrefix']) ? $config['controllerPrefix'] : __NAMESPACE__ . '\\'; $this->requestPath = explode('/', str_replace('\\', '/', strtolower($this->requestURI))); if (end($this->requestPath) === '') { array_pop($this->requestPath); } $this->requestPath = array_reverse($this->requestPath); if (end($this->requestPath) === '') { array_pop($this->requestPath); } } public function getRequestURI() { return $this->requestURI; } public function getRequestPath() { return $this->requestPath; } public function getAppMode() { return $this->appMode; } public function getLogger() { return $this->logger; } public function getControllerPrefix() { return $this->controllerPrefix; } } class HTTPNotFound extends \Exception { public function __construct($message = 'Resource not found!', $code = 0, Exception $previous = null) { parent::__construct($message, $code, $previous); } } class ScreenLog { public function __call($methodName, $args) { echo var_export($args, true) . "\n"; } } class RootController { public $home = 'HomeController'; public function __invoke($args = array()) { return "Root controller index"; } } class HomeController { public $home = 'HomeController'; public function __invoke($args = array()) { return "Home controller index"; } } $context = new Context([ 'requestURI' => '/home', 'logger' => new ScreenLog() ]); $dispatch = new ObjectDispatch(); try { foreach ($dispatch($context, 'RootController') as $signal) { list($object, $chunk, $path, $isEndpoint) = $signal; if ($isEndpoint) { if (!empty($chunk)) { echo $object->$chunk($path); } else { echo $object($path); } } } } catch (Exception $e) { echo "Bummer! " . $e->getMessage(); }
Output for git.master, git.master_jit, rfc.property-hooks
Fatal error: Uncaught Magnus\HTTPNotFound: Resource not found! in /in/N5CDi:99 Stack trace: #0 /in/N5CDi(214): Magnus\ObjectDispatch->__invoke(Object(Magnus\Context), 'RootController') #1 {main} thrown in /in/N5CDi on line 99
Process exited with code 255.

This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.

Active branches

Archived branches

Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page


preferences:
51.11 ms | 401 KiB | 8 Q