/** * @param string $route * @param array $constraints * @return array * @throws \RuntimeException */ protected function tokens($route, array $constraints = []) { $currentPos = 0; $length = strlen($route); $level = 0; $token = '(\\G(?P<literal>[^{}\\[\\]]*)(?P<token>[{}\\[\\]]|$))'; $tokens = []; $variable = '(\\G\\s*(?P<name>[a-zA-Z0-9_]++)?\\s*(?(1):)?\\s*(?P<constraint>[^{}]*(?:\\{(?-1)\\}[^{}]*)*)?)'; while ($currentPos < $length) { preg_match($token, $route, $match, 0, $currentPos); $currentPos += strlen($match[0]); '' !== $match['literal'] && ($tokens[] = ['literal', $match['literal']]); if ('{' === $match['token']) { preg_match($variable, $route, $match, 0, $currentPos); $currentPos += strlen($match[0]); $tokens[] = ['param', $match['name'], $this->expression($this->constraint($match['name'], $match['constraint'], $constraints))]; continue; } if ('[' === $match['token']) { $tokens[] = ['optional-start']; $level++; continue; } if (']' === $match['token']) { $tokens[] = ['optional-end']; --$level < 0 && Exception::runtime('Found closing bracket without matching opening bracket'); continue; } } $level > 0 && Exception::runtime('Found unbalanced brackets'); return $tokens; }
/** * @param array|Route $route * @param bool $compile * @param bool $recursive * @return array|Route */ protected function definition($route, $compile = true, $recursive = false) { $recursive && isset($route[Arg::CHILDREN]) && ($route[Arg::CHILDREN] = $this->children($route[Arg::CHILDREN], $compile, $recursive)); if (!isset($route[Arg::ROUTE])) { return isset($route[Arg::REGEX]) ? $route : Exception::invalidArgument('Route path not specified'); } !isset($route[Arg::TOKENS]) && ($route[Arg::TOKENS] = $this->tokens($route[Arg::ROUTE], isset($route[Arg::CONSTRAINTS]) ? $route[Arg::CONSTRAINTS] : [])); $compile && !isset($route[Arg::REGEX]) && ($route[Arg::REGEX] = $this->regex($route[Arg::TOKENS])); return $route; }
/** * */ function test_runtime_exception() { try { Exception::runtime('foo'); } catch (\Exception $exception) { } $this->assertEquals('foo', $exception->getMessage()); $this->assertEquals(__FILE__, $exception->getFile()); $this->assertEquals(22, $exception->getLine()); $this->assertInstanceOf(Runtime::class, $exception); }
/** * */ function test_invalid_argument_exception() { try { Exception::invalidArgument('foo'); } catch (\Exception $exception) { } $this->assertEquals('foo', $exception->getMessage()); $this->assertEquals(__FILE__, $exception->getFile()); $this->assertEquals(22, $exception->getLine()); $this->assertInstanceOf(InvalidArgument::class, $exception); }
/** * @param Route $parent * @param array|Route $route * @param array $path * @param bool $start * @return array|Route * @throws \RuntimeException */ function __invoke(Route $parent, $route, array $path, $start = false) { if ($root = $parent->child($path[0])) { return $this($root, $route, array_slice($path, 1)); } isset($path[1]) && Exception::runtime('Parent route not found: ' . $route[Arg::NAME]); $route[Arg::NAME] = $path[0]; $start && empty($route[Arg::ROUTE]) && isset($route[Arg::NAME]) && ($route[Arg::ROUTE] = $route[Arg::NAME]); !$start && empty($route[Arg::ROUTE]) && ($route[Arg::ROUTE] = Arg::SEPARATOR . $path[0]); $route = $this->definition($route); $parent->add($path[0], $route); return $route; }
/** * @param callable|object $config * @param array $args * @param callable $callback * @return mixed */ protected static function signal(callable $config, array $args = [], callable $callback = null) { if ($args && !is_string(key($args))) { return call_user_func_array($config, $args); } $function = null; $matched = []; $method = '__invoke'; $params = []; if (is_string($config)) { $static = explode('::', $config); if (isset($static[1])) { list($config, $method) = $static; } else { $params = (new ReflectionFunction($config))->getParameters(); $function = $config; } } is_array($config) && (list($config, $method) = $config); !$function && ($params = (new ReflectionMethod($config, $method))->getParameters()); foreach ($params as $param) { if (isset($args[$param->name])) { $matched[] = $args[$param->name]; continue; } if (Arg::ARGS === $param->name) { $matched[] = $param->isVariadic() ? new Plugin\SignalArgs($args) : $args; continue; } if ($param->isOptional()) { $param->isDefaultValueAvailable() && ($matched[] = $param->getDefaultValue()); continue; } if ($callback && null !== ($match = $callback($param->name))) { $matched[] = $match; continue; } if ($callback && ($hint = $param->getClass())) { $matched[] = $callback($hint->name); continue; } Exception::runtime('Missing required parameter $' . $param->name . ' for ' . ($function ?: (is_string($config) ? $config : get_class($config)))); } return call_user_func_array($function ?: [$config, $method], $params ? $matched : $args); }
/** * @param array $tokens * @param array $params * @param array $defaults * @param callable $wildcard * @return string * @throws \InvalidArgumentException */ protected function compile(array $tokens, array $params, array $defaults = null, callable $wildcard = null) { $current = ['is_optional' => false, 'skip' => true, 'skippable' => false, 'path' => '']; $stack = []; foreach ($tokens as $part) { if ('literal' === $part[Dash::TYPE]) { $current['path'] .= $part[Dash::LITERAL]; continue; } if ('param' === $part[Dash::TYPE]) { $current['skippable'] = true; if (!$part[Dash::NAME]) { continue; } $default = isset($defaults[$part[Dash::NAME]]) ? $defaults[$part[Dash::NAME]] : null; $path = isset($params[$part[Dash::NAME]]) ? $params[$part[Dash::NAME]] : null; if (!$path) { if ($current['is_optional']) { continue; } !$default && Exception::invalidArgument(sprintf('Missing parameter "%s"', $part[Dash::NAME])); $path = $default; } (!$current['is_optional'] || !$default || $default !== $path) && ($current['skip'] = false); $current['path'] .= $path; unset($params[$part[Dash::NAME]]); continue; } if ('optional-start' === $part[Dash::TYPE]) { $stack[] = $current; $current = ['is_optional' => true, 'skip' => true, 'skippable' => false, 'path' => '']; continue; } if ('optional-end' === $part[Dash::TYPE]) { $parent = array_pop($stack); if ($current['path'] === '' || !$current['is_optional'] || !$current['skippable'] || !$current['skip']) { $parent['path'] .= $current['path']; $parent['skip'] = false; } $current = $parent; continue; } } return $wildcard && $params ? $wildcard(rtrim($current['path'], Arg::SEPARATOR), $params) : $current['path']; }
/** * */ function test_runtime() { $this->setExpectedException(Runtime::class, 'foo'); Exception::runtime('foo'); }
/** * @param \Exception|mixed|null $exception * @param \Exception|mixed|null $message * @param bool $throw_exception * @return \Exception|mixed|null * @throws \Exception */ function __invoke($exception = null, $message = null, $throw_exception = false) { $throw_exception && $message instanceof \Exception && _Exception::raise($message); $throw_exception && $exception instanceof \Exception && _Exception::raise($exception); return $exception ?: $message; }
/** * @param string $name * @return null */ protected function initializing($name) { !empty($this->pending[$name]) && Exception::runtime('Circular dependency: ' . $name); $this->pending[$name] = true; return null; }
/** * @return callable|Manager|Service */ static function service() { return static::$service ?: Exception::runtime('Service does not exist'); }
/** * @param string $name * @param null $config * @return null|object|callable */ protected function initialize($name, $config = null) { !empty($this->pending[$name]) && Exception::runtime('Circular dependency: ' . $name); $this->pending[$name] = true; return $this->initialized($name, $this->plugin($config ?: $name)); }
/** * @param string $name * @param array $args * @return callable|object */ protected function make($name, array $args = []) { $class = new \ReflectionClass($name); if (!$class->hasMethod('__construct')) { return $class->newInstanceWithoutConstructor(); } if ($args && !is_string(key($args))) { return $class->newInstanceArgs($args); } $matched = []; $params = $class->getConstructor()->getParameters(); foreach ($params as $param) { if (isset($args[$param->name])) { $matched[] = $args[$param->name]; continue; } if ($param->isOptional()) { $param->isDefaultValueAvailable() && ($matched[] = $param->getDefaultValue()); continue; } if (null !== ($hint = $param->getClass()) && null !== ($match = $this($hint->name))) { $matched[] = $match; continue; } if (null !== ($match = $this($param->name))) { $matched[] = $match; continue; } Exception::runtime('Missing required parameter $' . $param->name . ' for ' . $name); } return $class->newInstanceArgs($params ? $matched : $args); }