Question

I have a relatively simple function which uses a foreach

function foo($t) {
     $result;
     foreach($t as $val) {
         $result = dosomething($result, $val);
     }
     return $result;
}

I would like to type hint, and Traversable seems to be the exact type hint I need

 function foo(Traversable $t) {

However this gives a E_RECOVERABLE_ERROR when using an array (which is of course usable in a foreach): example

 Argument 1 passed to foo() must implement interface Traversable, array given

Is there a way to type hint or is this not possible?

Was it helpful?

Solution

PHP 7.1 introduces the iterable type declaration for this purpose, which accepts both arrays and instances of \Traversable.

In previous versions, you'll have to omit the type declaration.

OTHER TIPS

There is a bug about this: #41942. Closed as 'not a bug'. As PHP arrays are not objects they cannot implement an interface and a such there is no way to type hint both array and Traversable.

You can use iterator_to_array, ArrayIterator or omit the type hint. Note that iterator_to_array will copy the whole iterator into an array an might thus be inefficient.

// These functions are functionally equivalent but do not all accept the same arguments
function foo(array $a) { foobar($a); }
function bar(Traversable $a) { foobar($a); }
function foobar($a) {
    foreach($a as $key => $value) {
    }
}

$array = array(1,2,3)
$traversable = new MyTraversableObject();

foo($array);
foo(iterator_to_array($traversable));

bar(new ArrayIterator($array));
bar($traversable);

foobar($array);
foobar($traversable);

Same problem. I've given up I simply manually code everything in the function.

This should give you the functionality you want:

function MyFunction($traversable)
{
    if(!$traversable instanceof Traversable && !is_array($traversable))
    {
        throw new InvalidArgumentException(sprintf(
            'Myfunction($traversable = %s): Invalid argument $traversable.'
            ,var_export($traversable, true)
       ));
    }
}

EDIT

If you only want to display type of $traversable. And if you want the functionality inheritable in child classes.

public function MyMethod($traversable)
{
    if(!$traversable instanceof Traversable && !is_array($traversable))
    {
        throw new InvalidArgumentException(sprintf(
            '%s::MyMethod($traversable): Invalid argument $traversable of type `%s`.'
            ,get_class($this)
            ,gettype($traversable)
       ));
    }
}

The problem is, that arrays are no objects, so they can't implement an interface. So you can't type hint both, array and Traversable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top