3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features
<?php namespace Magnus; class ObjectDispatch { 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, $chunk, $path, true); } elseif (is_callable($parent)) { yield array($parent, $chunk, $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('\\', '/', $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 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"; } } $context = new Context([ 'requestURI' => '/', 'logger' => new ScreenLog() ]); $dispatch = new ObjectDispatch(); foreach ($dispatch($context, 'RootController') as $signal) { list($object, $chunk, $path, $isEndpoint) = $signal; if ($isEndpoint) { echo $object->$chunk($path); } }
based on 2Yu0W
Output for 7.0.0 - 7.2.0
Notice: Undefined variable: chunk in /in/ONGbJ on line 117 Fatal error: Uncaught Error: Method name must be a string in /in/ONGbJ:197 Stack trace: #0 {main} thrown in /in/ONGbJ on line 197
Process exited with code 255.
Output for 5.5.0 - 5.6.28
Notice: Undefined variable: chunk in /in/ONGbJ on line 117 Fatal error: Method name must be a string in /in/ONGbJ on line 197
Process exited with code 255.