<?php 
 
/* 
 * This file is part of Chevere. 
 * 
 * (c) Rodolfo Berrios <[email protected]> 
 * 
 * For the full copyright and license information, please view the LICENSE 
 * file that was distributed with this source code. 
 */ 
 
declare(strict_types=1); 
 
namespace Chevere\Parameter; 
 
use Chevere\Parameter\Interfaces\TypeInterface; 
use InvalidArgumentException; 
use function Chevere\Message\message; 
 
final class Type implements TypeInterface 
{ 
    public const CLASS_TYPES = [ 
        self::PRIMITIVE_CLASS_NAME, 
        self::PRIMITIVE_INTERFACE_NAME, 
    ]; 
 
    private string $validator; 
 
    private string $primitive = ''; 
 
    private string $typeHinting = ''; 
 
    /** 
     * @param string $type A debug type 
     */ 
    public function __construct( 
        private string $type 
    ) { 
        $this->setPrimitive(); 
        $this->assertHasPrimitive(); 
        $this->validator = self::TYPE_VALIDATORS[$this->primitive]; 
        $this->typeHinting = $this->primitive; 
        if (in_array($this->primitive, self::CLASS_TYPES, true)) { 
            $this->typeHinting = $this->type; 
        } 
    } 
 
    public function validator(): callable 
    { 
        /** @var callable */ 
        return $this->validator; // @phpstan-ignore-line 
    } 
 
    public function primitive(): string 
    { 
        return $this->primitive; 
    } 
 
    public function typeHinting(): string 
    { 
        return $this->typeHinting; 
    } 
 
    public function validate(mixed $variable): bool 
    { 
        if (is_object($variable) && $this->isAbleToValidateObjects()) { 
            return $this->validateObject($variable); 
        } 
 
        return $this->validator()($variable); 
    } 
 
    public function isScalar(): bool 
    { 
        return in_array($this->primitive, ['bool', 'int', 'float', 'string'], true); 
    } 
 
    private function isAbleToValidateObjects(): bool 
    { 
        return in_array($this->primitive, self::CLASS_TYPES, true); 
    } 
 
    private function validateObject(object $object): bool 
    { 
        return $object instanceof $this->type; 
    } 
 
    private function setPrimitive(): void 
    { 
        if (in_array($this->type, self::TYPE_ARGUMENTS, true)) { 
            $this->primitive = $this->type; 
 
            return; 
        } 
 
        if (class_exists($this->type)) { 
            $this->primitive = self::PRIMITIVE_CLASS_NAME; 
        } elseif (interface_exists($this->type)) { 
            $this->primitive = self::PRIMITIVE_INTERFACE_NAME; 
        } 
    } 
 
    private function assertHasPrimitive(): void 
    { 
        if ($this->primitive === '') { 
            throw new InvalidArgumentException( 
                (string) message( 
                    "Type `%type%` doesn't exists", 
                    type: $this->type 
                ) 
            ); 
        } 
    } 
} 
 
 |