programing

반복 가능한 객체 및 배열 유형 힌트?

itsource 2021. 1. 18. 07:59
반응형

반복 가능한 객체 및 배열 유형 힌트?


배열에 대한 유형 힌트가 있거나 is_array()변수의 배열 여부를 확인하는 데 사용하는 많은 함수가 있습니다 .

이제 반복 가능한 객체를 사용하기 시작했습니다. 그들은 Iterator또는 IteratorAggregate. 유형 힌트를 통과하면 배열로 허용 is_array()됩니까?

내 코드를 수정해야하는 경우, 일반적인 종류가 있습니까 is_iterable(), 아니면 다음과 같이해야합니까?

if ( is_array($var) OR $var instance_of Iterable OR $var instanceof IteratorAggregate ) { ... }

어떤 다른 반복 가능한 인터페이스가 있습니까?


instanceof Iterator, PHP에는 Iterable인터페이스 가 없다고 생각합니다 . Traversable그래도 인터페이스 가 있습니다 . Iterator그리고 IteratorAggregate둘 다 확장합니다 Traversable(그리고 AFAIK는 그렇게 할 유일한 사람입니다).

그러나 아니요, 구현하는 객체 Traversableis_array()검사를 통과하지 못하며 내장 is_iterable()기능도 없습니다. 사용할 수있는 수표는

function is_iterable($var) {
    return (is_array($var) || $var instanceof Traversable);
}

명확하게하기 위해, 모든 PHP는 객체의 foreach와 반복,하지만 할 수있는 몇 가지 그들의 구현 Traversable. 따라서 제시된 is_iterable함수는 foreach가 처리 할 수있는 모든 것을 감지하지 않습니다.


PHP 7.1.0 이러한 목적을 위해 특별히 설계된 iterablepseudo-type 및 is_iterable()함수를 도입 했습니다 .

이것은 […] 새로운 iterable의사 유형을 제안합니다 . 이 유형은 callable하나의 단일 유형 대신 여러 유형을 허용 하는와 유사 합니다.

iterablearray또는 객체 구현을 허용합니다 Traversable. 이 두 유형은 모두 반복 가능하며 생성기 내에서 foreach사용할 수 있습니다 yield.

function foo(iterable $iterable) {
    foreach ($iterable as $value) {
        // ...
    }
}

이 […]는 또한 is_iterable()부울을 반환 하는 함수 추가 true합니다. 값이 반복 가능하고 다른 값에 대해 iterable의사 유형에서 허용되는 경우 false.

var_dump(is_iterable([1, 2, 3])); // bool(true)
var_dump(is_iterable(new ArrayIterator([1, 2, 3]))); // bool(true)
var_dump(is_iterable((function () { yield 1; })())); // bool(true)
var_dump(is_iterable(1)); // bool(false)
var_dump(is_iterable(new stdClass())); // bool(false)

stdClass의 인스턴스가 foreach 루프에서 작동하기 때문에 실제로 stdClass에 대한 검사를 추가해야했지만 stdClass는 Traversable을 구현하지 않습니다.

function is_iterable($var) {
    return (is_array($var) || $var instanceof Traversable || $var instanceof stdClass);
}

나는 "반복성"을 테스트하기 위해 간단한 방법을 사용합니다.

function is_iterable($var) {
    set_error_handler(function ($errno, $errstr, $errfile, $errline, array $errcontext)
    {
        throw new \ErrorException($errstr, null, $errno, $errfile, $errline);
    });

    try {
        foreach ($var as $v) {
            break;
        }
    } catch (\ErrorException $e) {
        restore_error_handler();
        return false;
    }
    restore_error_handler();
    return true;
}

반복 불가능한 변수를 반복하려고하면 PHP가 경고를 표시합니다. 반복을 시도하기 전에 사용자 지정 오류 처리기를 설정하면 오류를 예외로 변환하여 try / catch 블록을 사용할 수 있습니다. 나중에 프로그램 흐름을 방해하지 않도록 이전 오류 처리기를 복원합니다.

다음은 작은 테스트 케이스입니다 (PHP 5.3.15에서 테스트 됨).

class Foo {
    public $a = 'one';
    public $b = 'two';
}

$foo = new Foo();
$bar = array('d','e','f');
$baz = 'string';
$bazinga = 1;
$boo = new StdClass();    

var_dump(is_iterable($foo)); //boolean true
var_dump(is_iterable($bar)); //boolean true
var_dump(is_iterable($baz)); //boolean false
var_dump(is_iterable($bazinga)); //bolean false
var_dump(is_iterable($boo)); //bolean true

불행히도 당신은 이것에 대해 타입 힌트를 사용할 수 없을 것이고 그 일을해야 할 것이다 is_array($var) or $var instanceof ArrayAccess. 이것은 알려진 문제이지만 아직 해결되지 않았습니다. 적어도 방금 테스트 한 PHP 5.3.2에서는 작동하지 않습니다.


반복 가능한 객체를 사용하도록 전환하면 유형 힌트를 사용할 수 있습니다.

protected function doSomethingWithIterableObject(Iterator $iterableObject) {}

또는

protected function doSomethingWithIterableObject(Traversable $iterableObject) {}

그러나 이것은 반복 가능한 객체와 배열을 동시에 받아들이는 데 사용할 수 없습니다. 정말로 그렇게하고 싶다면 다음과 같은 래퍼 함수를 ​​만들 수 있습니다.

// generic function (use name of original function) for old code
// (new code may call the appropriate function directly)
public function doSomethingIterable($iterable)
{
    if (is_array($iterable)) {
        return $this->doSomethingIterableWithArray($iterable);
    }
    if ($iterable instanceof Traversable) {
        return $this->doSomethingIterableWithObject($iterable);
    }
    return null;
}
public function doSomethingIterableWithArray(array $iterable)
{
    return $this->myIterableFunction($iterable);
}
public function doSomethingIterableWithObject(Iterator $iterable)
{
    return $this->myIterableFunction($iterable);
}
protected function myIterableFunction($iterable)
{
    // no type checking here
    $result = null;
    foreach ($iterable as $item)
    {
        // do stuff
    }
    return $result;
}

ReferenceURL : https://stackoverflow.com/questions/3584700/iterable-objects-and-array-type-hinting

반응형