PHP:检查变量是否满足字符串中的类型定义

问题描述 投票:0回答:1

有没有办法测试

$var
是否满足除此之外的字符串中定义的类型:

function test_type(mixed $value, string $type): bool 
{
    try { 
          eval('(fn('.$type.' $a)=>true)($value);'); 
          return true;  
    }  
    catch (Throwable  $e) { 
          return false; 
    }
}
test_type(null,  "int") ; // returns false. 
test_type(null,  "?int") ; // return true. 
test_type("hello, world", "bool") ; // returns true. I want it to return false
test_type(new DateTime, "DateTimeInterface") ; // return true. 
test_type(new DateTime, "null|int|DateTime|DateTimeImmutable") ; // return true

这种方法有两个不需要进一步解释的主要问题:

  • 评估
  • 自动类型转换(如
    test_type("hello, world", "bool")
    =>
    true

有没有办法避免这些问题呢?我用谷歌搜索了很多,但到目前为止还没有找到任何东西。

php typing typeof type-testing
1个回答
0
投票

@Jaquarh 让我相信,通过真正的测试,这比我想象的要容易得多。他的版本是这个解决方案的基础。谢谢,贾夸!

我没有使用资源进行测试,因为我不存储它们,如果有人想使用资源添加答案,请这样做。

<?php

function test_type(mixed $value, string $type): bool
{   $foundType =  strtolower(gettype($value)); 
    $foundType = ['boolean'=>'bool', 'integer'=>'int', 'double'=>'float'][$foundType] ?? $foundType;
    
    $type = str_replace('?', 'null|', $type);
    $typesUnion = explode('|', $type);
    $typesIntersection = explode('&', $type);
    if ( count($typesIntersection)>1) {
        if (  ! is_object($value) ) return false;
        foreach($typesIntersection as $subtype) {
            if ( ! ($value instanceof $subtype)) return false;
        }
        return true;
    }
    foreach($typesUnion as $subtype) {

        if ( is_null($value) && strtolower($subtype)=='null' )  return true;       
        if ( $value === false && strtolower($subtype)=='false' )  return true;       
        if ( $value === true && strtolower($subtype)=='true' )  return true;       
        if ( is_callable($value) && strtolower($subtype)=='callable' )  return true;       
        if ( is_object($value) ) { if ( $value instanceof $subtype) return true; }
        elseif ( $foundType == strtolower($subtype) ) return true;
    }
    return false;
}

enum hello { case world; case earth; case mars; };

echo (int) test_type(false,  "int|bool");                                   // 1
echo (int) test_type(null,  "?int");                                        // 1
echo (int) test_type(null,  "int|string");                                  // 0
echo (int) test_type("hello, world", "?bool");                              // 0
echo (int) test_type(hello::world, "hello");                                // 1
echo (int) test_type(false, "DateTimeInterface|false");                     // 1
echo (int) test_type(true, "DateTimeInterface|false");                      // 0
echo (int) test_type(new DateTime, "DateTimeInterface|false");              // 1
echo (int) test_type(new DateTime, "null|int|DateTime|DateTimeImmutable");  // 1
echo (int) test_type(new DateTime, "DateTime&DateTimeInterface");           // 1
echo (int) test_type([1,2,3,4], "Array");                                   // 1
echo (int) test_type(fn($x) => $x+1, "callable");                           // 1

https://onlinephp.io/c/fea67

© www.soinside.com 2019 - 2024. All rights reserved.