Skip to content

Commit

Permalink
Initial import of code from @MichelHartmann that was contributed to P…
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianbergmann committed May 19, 2019
1 parent 3553621 commit 9c02491
Show file tree
Hide file tree
Showing 17 changed files with 924 additions and 0 deletions.
5 changes: 5 additions & 0 deletions composer.json
Expand Up @@ -34,6 +34,11 @@
"src/"
]
},
"autoload-dev": {
"classmap": [
"tests/_fixture"
]
},
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
Expand Down
32 changes: 32 additions & 0 deletions src/NullType.php
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class NullType extends Type
{
public function isAssignable(Type $other): bool
{
return !($other instanceof VoidType);
}

public function getReturnTypeDeclaration(): string
{
return '';
}

public function allowsNull(): bool
{
return true;
}
}
62 changes: 62 additions & 0 deletions src/ObjectType.php
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class ObjectType extends Type
{
/**
* @var TypeName
*/
private $className;

/**
* @var bool
*/
private $allowsNull;

public function __construct(TypeName $className, bool $allowsNull)
{
$this->className = $className;
$this->allowsNull = $allowsNull;
}

public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
if ($this->className->getQualifiedName() === $other->className->getQualifiedName()) {
return true;
}

if (\is_subclass_of($other->className->getQualifiedName(), $this->className->getQualifiedName(), true)) {
return true;
}
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . $this->className->getQualifiedName();
}

public function allowsNull(): bool
{
return $this->allowsNull;
}
}
75 changes: 75 additions & 0 deletions src/SimpleType.php
@@ -0,0 +1,75 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class SimpleType extends Type
{
/**
* @var string
*/
private $name;

/**
* @var bool
*/
private $allowsNull;

public function __construct(string $name, bool $nullable)
{
$this->name = $this->normalize($name);
$this->allowsNull = $nullable;
}

public function isAssignable(Type $other): bool
{
if ($this->allowsNull && $other instanceof NullType) {
return true;
}

if ($other instanceof self) {
return $this->name === $other->name;
}

return false;
}

public function getReturnTypeDeclaration(): string
{
return ': ' . ($this->allowsNull ? '?' : '') . $this->name;
}

public function allowsNull(): bool
{
return $this->allowsNull;
}

private function normalize(string $name): string
{
$name = \mb_strtolower($name);

switch ($name) {
case 'boolean':
return 'bool';
case 'real':
case 'double':
return 'float';
case 'integer':
return 'int';
case '[]':
return 'array';
default:
return $name;
}
}
}
65 changes: 65 additions & 0 deletions src/Type.php
@@ -0,0 +1,65 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
abstract class Type
{
public static function fromValue($value, bool $allowsNull): self
{
$type = \gettype($value);

if ($type === 'object') {
return new ObjectType(TypeName::fromQualifiedName(\get_class($value)), $allowsNull);
}

return self::fromName($type, $allowsNull);
}

public static function fromName(string $typeName, bool $allowsNull): self
{
switch (\strtolower($typeName)) {
case 'null':
return new NullType;

case 'unknown type':
return new UnknownType;

case 'void':
return new VoidType;

case 'object':
case 'boolean':
case 'bool':
case 'integer':
case 'int':
case 'real':
case 'double':
case 'float':
case 'string':
case 'array':
case 'resource':
case 'resource (closed)':
return new SimpleType($typeName, $allowsNull);

default:
return new ObjectType(TypeName::fromQualifiedName($typeName), $allowsNull);
}
}

abstract public function isAssignable(self $other): bool;

abstract public function getReturnTypeDeclaration(): string;

abstract public function allowsNull(): bool;
}
81 changes: 81 additions & 0 deletions src/TypeName.php
@@ -0,0 +1,81 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class TypeName
{
/**
* @var ?string
*/
private $namespaceName;

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

public static function fromQualifiedName(string $fullClassName): self
{
if ($fullClassName[0] === '\\') {
$fullClassName = \substr($fullClassName, 1);
}

$classNameParts = \explode('\\', $fullClassName);

$simpleName = \array_pop($classNameParts);
$namespaceName = \implode('\\', $classNameParts);

return new self($namespaceName, $simpleName);
}

public static function fromReflection(\ReflectionClass $type): self
{
return new self(
$type->getNamespaceName(),
$type->getShortName()
);
}

public function __construct(?string $namespaceName, string $simpleName)
{
if ($namespaceName === '') {
$namespaceName = null;
}

$this->namespaceName = $namespaceName;
$this->simpleName = $simpleName;
}

public function getNamespaceName(): ?string
{
return $this->namespaceName;
}

public function getSimpleName(): string
{
return $this->simpleName;
}

public function getQualifiedName(): string
{
return $this->namespaceName === null
? $this->simpleName
: $this->namespaceName . '\\' . $this->simpleName;
}

public function isNamespaced(): bool
{
return $this->namespaceName !== null;
}
}
32 changes: 32 additions & 0 deletions src/UnknownType.php
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class UnknownType extends Type
{
public function isAssignable(Type $other): bool
{
return true;
}

public function getReturnTypeDeclaration(): string
{
return '';
}

public function allowsNull(): bool
{
return true;
}
}
32 changes: 32 additions & 0 deletions src/VoidType.php
@@ -0,0 +1,32 @@
<?php declare(strict_types=1);
/*
* This file is part of sebastian/type.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianBergmann\Type;

/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final class VoidType extends Type
{
public function isAssignable(Type $other): bool
{
return $other instanceof self;
}

public function getReturnTypeDeclaration(): string
{
return ': void';
}

public function allowsNull(): bool
{
return false;
}
}

0 comments on commit 9c02491

Please sign in to comment.