protected static function make(string $namespace, string $type_name, $template_parameter_type_list) : Type
{
$namespace = trim($namespace);
if ('\\' === $namespace) {
$type_name = self::canonicalNameFromName($type_name);
}
// If this looks like a generic type string, explicitly
// make it as such
if (self::isGenericArrayString($type_name) && ($pos = strrpos($type_name, '[]')) !== false) {
return GenericArrayType::fromElementType(Type::make($namespace, substr($type_name, 0, $pos), $template_parameter_type_list));
}
assert($namespace && 0 === strpos($namespace, '\\'), "Namespace must be fully qualified");
assert(!empty($namespace), "Namespace cannot be empty");
assert('\\' === $namespace[0], "Namespace must be fully qualified");
assert(!empty($type_name), "Type name cannot be empty");
assert(false === strpos($type_name, '|'), "Type name may not contain a pipe.");
// Create a canonical representation of the
// namespace and name
$namespace = $namespace ?: '\\';
if ('\\' === $namespace) {
$type_name = self::canonicalNameFromName($type_name);
}
// Make sure we only ever create exactly one
// object for any unique type
static $canonical_object_map = [];
$key = $namespace . '\\' . $type_name;
if ($template_parameter_type_list) {
$key .= '<' . implode(',', array_map(function (UnionType $union_type) {
return (string) $union_type;
}, $template_parameter_type_list)) . '>';
}
$key = strtolower($key);
if (empty($canonical_object_map[$key])) {
$canonical_object_map[$key] = new static($namespace, $type_name, $template_parameter_type_list);
}
return $canonical_object_map[$key];
}