@ 2016-01-12T11:14:37Z <?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;
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($context->getControllerPrefix() . $current)) {
if ($context->getAppMode() === 'DEBUG' && $log !== null) {
$log->addDebug('Instantiating current class', [
'request' => $context->getRequestURI(),
'current' => $current
]);
}
$current = $context->getControllerPrefix() . $current($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($context->getControllerPrefix() . $current)) {
$current = new $current($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);
}
}
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Output for git.master , git.master_jit , rfc.property-hooks Fatal error: Uncaught Error: Class "RootController" not found in /in/1UfmL:110
Stack trace:
#0 /in/1UfmL(191): Magnus\ObjectDispatch->__invoke(Object(Magnus\Context), 'RootController')
#1 {main}
thrown in /in/1UfmL on line 110
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:dark mode live preview
35.14 ms | 401 KiB | 8 Q