src/Router/UriGenerator.php
protected function resolveParams(UriInfo $info, array $params)
	{
		$uri = $info->getUri();
		
		if(false === strpos($uri, '{'))
		{
			return $info;
		}
	
		$ctx = NULL;
		$result = '';
		
		foreach(preg_split("'(\\{[^\\}]+\\})'", $uri, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $part)
		{
			if('{' != substr($part, 0, 1))
			{
				$result .= $part;
	
				continue;
			}
				
			$placeholder = substr($part, 1, -1);
				
			if('*' == substr($placeholder, -1))
			{
				$placeholder = substr($placeholder, 0, -1);
				$multi = true;
			}
			else
			{
				$multi = false;
			}
				
			switch(substr($placeholder, 0, 1))
			{
				case '.':
					$placeholder = substr($placeholder, 1);
					$prefix = '.';
					$join = $multi ? '.' : ',';
					break;
				case '/':
					$placeholder = substr($placeholder, 1);
					$prefix = '/';
					$join = $multi ? '/' : ',';
					break;
				default:
					$prefix = '';
					$join = ',';
			}
				
			if(false === strpos($placeholder, '.'))
			{
				$value = array_key_exists($placeholder, $params) ? $params[$placeholder] : $this;
			}
			else
			{
				if($ctx === NULL)
				{
					$ctx = $this->factory->createContext($params);
				}
	
				$value = $ctx->resolveValue(explode('.', $placeholder), $this);
			}
				
			if($value === $this)
			{
				$result .= $part;
			}
			elseif(is_array($value) || $value instanceof \Traversable)
			{
				$i = 0;
	
				foreach($value as $val)
				{
					$result .= (($i++ == 0) ? $prefix : $join) . Uri::encode($val, true);
				}
			}
			else
			{
				$result .= $prefix . Uri::encode($value, true);
			}
		}
	
		return new UriInfo($result, $info->getRouteName(), $info->getMethods(), $info->getHandler());
	}
protected function resolveParams(UriInfo $info, array $params)
	{
		$uri = $info->getUri();
		
		if(false === strpos($uri, '{'))
		{
			return $info;
		}
	
		$ctx = NULL;
		$result = '';
		
		foreach(preg_split("'(\\{[^\\}]+\\})'", $uri, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $part)
		{
			if('{' != substr($part, 0, 1))
			{
				$result .= $part;
	
				continue;
			}
				
			$placeholder = substr($part, 1, -1);
				
			if('*' == substr($placeholder, -1))
			{
				$placeholder = substr($placeholder, 0, -1);
				$multi = true;
			}
			else
			{
				$multi = false;
			}
				
			switch(substr($placeholder, 0, 1))
			{
				case '.':
					$placeholder = substr($placeholder, 1);
					$prefix = '.';
					$join = $multi ? '.' : ',';
					break;
				case '/':
					$placeholder = substr($placeholder, 1);
					$prefix = '/';
					$join = $multi ? '/' : ',';
					break;
				default:
					$prefix = '';
					$join = ',';
			}
				
			if(false === strpos($placeholder, '.'))
			{
				$value = array_key_exists($placeholder, $params) ? $params[$placeholder] : $this;
			}
			else
			{
				if($ctx === NULL)
				{
					$ctx = $this->factory->createContext($params);
				}
	
				$value = $ctx->resolveValue(explode('.', $placeholder), $this);
			}
				
			if($value === $this)
			{
				$result .= $part;
			}
			elseif(is_array($value) || $value instanceof \Traversable)
			{
				$i = 0;
	
				foreach($value as $val)
				{
					$result .= (($i++ == 0) ? $prefix : $join) . Uri::encode($val, true);
				}
			}
			else
			{
				$result .= $prefix . Uri::encode($value, true);
			}
		}
	
		return new UriInfo($result, $info->getRouteName(), $info->getMethods(), $info->getHandler());
	}
Resolve and replace parameter values in the assembled URI.

@param UriInfo $info
@param array<string, mixed> $params
@return UriInfo