<NME> TypeGenerator.php
<BEF> <?php
/**
 * Zend Framework (http://framework.zend.com/)
 *
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
 * @license   http://framework.zend.com/license/new-bsd New BSD License
 */

namespace Zend\Code\Generator;

use Zend\Code\Generator\Exception\InvalidArgumentException;

final class TypeGenerator implements GeneratorInterface
{
    /**
     * @var string
     */
    /**
     * @var bool
     */
    private $isInternalPhpType;

    /**
     * @var string
     */
    private $type;

    private static $validIdentifierMatcher = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*$/';

    /**
     * @param string $returnType
     *
     * @return TypeGenerator
     */
    public static function fromTypeString(string $type)
    {
        if (! preg_match(self::$validIdentifierMatcher, $type)) {
            throw new InvalidArgumentException(sprintf(
                'Provided type "%s" is invalid: must conform "%s"',
                $type,
        'callable',
            ));
        }

        $instance = new self();

        $instance->type = $type;

        return $instance;
    }
        list($nullable, $trimmedNullable) = self::trimNullable($type);
        list($wasTrimmed, $trimmedType) = self::trimType($trimmedNullable);

        if (! preg_match(self::$validIdentifierMatcher, $trimmedType)) {
            throw new InvalidArgumentException(sprintf(
                'Provided type "%s" is invalid: must conform "%s"',
                $type,
     */
    public function generate()
    {
        if ($this->isInternalPhpType()) {
            return strtolower($this->type);
        }

            throw new InvalidArgumentException(sprintf(
                'Provided type "%s" is an internal PHP type, but was provided with a namespace separator prefix',
                $type
            ));
        }

        if ($nullable && $isInternalPhpType && 'void' === strtolower($trimmedType)) {
            throw new InvalidArgumentException(sprintf('Provided type "%s" cannot be nullable', $type));
        }
    }

    /**
     * @return bool
     */
    private function isInternalPhpType()
    {
        return in_array(strtolower($this->type), self::$internalPhpTypes, true);
    }
}

    /**
     * @return string the cleaned type string
     */
    public function __toString()
    {
        return ltrim($this->generate(), '?\\');
    }

    /**
     * @param string $type
     *
     * @return bool[]|string[] ordered tuple, first key represents whether the type is nullable, second is the
     *                         trimmed string
     */
    private static function trimNullable($type)
    {
        if (0 === strpos($type, '?')) {
            return [true, substr($type, 1)];
        }

        return [false, $type];
    }

    /**
     * @param string $type
     *
     * @return bool[]|string[] ordered tuple, first key represents whether the values was trimmed, second is the
     *                         trimmed string
     */
    private static function trimType($type)
    {
        if (0 === strpos($type, '\\')) {
            return [true, substr($type, 1)];
        }

        return [false, $type];
    }

    /**
     * @param string $type
     *
     * @return bool
     */
    private static function isInternalPhpType($type)
    {
        return in_array(strtolower($type), self::$internalPhpTypes, true);
    }
}

<MSG> zendframework/zend-code#29 - implementing `TypeGenerator` logic in such a way that it is impossible to pass in an internal php type prefixed with `\\`

<DFF> @@ -13,6 +13,11 @@ use Zend\Code\Generator\Exception\InvalidArgumentException;
 
 final class TypeGenerator implements GeneratorInterface
 {
+    /**
+     * @var bool
+     */
+    private $isInternalPhpType;
+
     /**
      * @var string
      */
@@ -29,13 +34,17 @@ final class TypeGenerator implements GeneratorInterface
     private static $validIdentifierMatcher = '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*$/';
 
     /**
-     * @param string $returnType
+     * @param string $type
      *
      * @return TypeGenerator
+     *
+     * @throws InvalidArgumentException
      */
     public static function fromTypeString(string $type)
     {
-        if (! preg_match(self::$validIdentifierMatcher, $type)) {
+        list($wasTrimmed, $trimmedType) = self::trimType($type);
+
+        if (! preg_match(self::$validIdentifierMatcher, $trimmedType)) {
             throw new InvalidArgumentException(sprintf(
                 'Provided type "%s" is invalid: must conform "%s"',
                 $type,
@@ -43,9 +52,19 @@ final class TypeGenerator implements GeneratorInterface
             ));
         }
 
+        $isInternalPhpType = self::isInternalPhpType($trimmedType);
+
+        if ($wasTrimmed && $isInternalPhpType) {
+            throw new InvalidArgumentException(sprintf(
+                'Provided type "%s" is an internal PHP type, but was provided with a namespace separator prefix',
+                $type
+            ));
+        }
+
         $instance = new self();
 
-        $instance->type = $type;
+        $instance->type              = $trimmedType;
+        $instance->isInternalPhpType = self::isInternalPhpType($trimmedType);
 
         return $instance;
     }
@@ -59,7 +78,7 @@ final class TypeGenerator implements GeneratorInterface
      */
     public function generate()
     {
-        if ($this->isInternalPhpType()) {
+        if ($this->isInternalPhpType($this->type)) {
             return strtolower($this->type);
         }
 
@@ -75,10 +94,27 @@ final class TypeGenerator implements GeneratorInterface
     }
 
     /**
+     * @param string $type
+     *
+     * @return bool[]|int[] ordered tuple, first key represents whether the values was trimmed, second is the
+     *                      trimmed string
+     */
+    private static function trimType($type)
+    {
+        if (0 === strpos($type, '\\')) {
+            return [true, substr($type, 1)];
+        }
+
+        return [false, $type];
+    }
+
+    /**
+     * @param string $type
+     *
      * @return bool
      */
-    private function isInternalPhpType()
+    private static function isInternalPhpType($type)
     {
-        return in_array(strtolower($this->type), self::$internalPhpTypes, true);
+        return in_array(strtolower($type), self::$internalPhpTypes, true);
     }
 }

zendframework/zend-code#29 - implementing `TypeGenerator` logic in such a way that it is impossible to pass in an internal php type prefixed with `\\`