Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/235.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Iterable对象和数组类型提示?_Php_Iterator_Type Hinting - Fatal编程技术网

Php Iterable对象和数组类型提示?

Php Iterable对象和数组类型提示?,php,iterator,type-hinting,Php,Iterator,Type Hinting,我有很多函数,它们要么为数组提供类型提示,要么使用is\u array()检查变量的数组性 现在我开始使用可编辑的对象。它们实现了Iterator或IteratorAggregate。如果它们通过类型暗示,或者经过is\u array(),它们会被接受为数组吗 如果我必须修改我的代码,是否有一种通用的is\u iterable(),或者我必须执行以下操作: 如果(是Iterable的数组($var)或$var instance_或IteratorAggregate的$var instanceof

我有很多函数,它们要么为数组提供类型提示,要么使用
is\u array()
检查变量的数组性

现在我开始使用可编辑的对象。它们实现了
Iterator
IteratorAggregate
。如果它们通过类型暗示,或者经过
is\u array()
,它们会被接受为数组吗

如果我必须修改我的代码,是否有一种通用的
is\u iterable()
,或者我必须执行以下操作:

如果(是Iterable的数组($var)或$var instance_或IteratorAggregate的$var instanceof){…}

还有哪些其他可移植接口?

不幸的是,您无法为此使用类型提示,必须执行
is\u array($var)或$var instanceof ArrayAccess

东西这是一个已知的问题,但似乎仍未解决。至少它不适用于我刚刚测试的PHP5.3.2。

我想你指的是instanceof
迭代器
,PHP没有一个
Iterable
接口。不过它确实有一个接口
Iterator
IteratorAggregate
都扩展了
Traversable
(而且他们是唯一这样做的人)

但是没有,实现
可遍历的
对象不会通过
is_array()
检查,也没有内置的
is_iterable()
函数。你可以用的支票是

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

需要明确的是,所有的php对象都可以用foreach进行迭代,但是只有其中的一些实现了
可遍历的
。因此,提供的
是可编辑的
函数不会检测foreach可以处理的所有事情。

如果切换到使用可编辑对象,则可以使用类型提示

protected function doSomethingWithIterableObject(Iterator $iterableObject) {}

但是,这不能用于同时接受iterable对象和数组。如果您确实想这样做,可以尝试构建一个包装函数,如下所示:

// 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;
}

实际上,我必须为stdClass添加一个检查,因为stdClass的实例在foreach循环中工作,但stdClass没有实现可遍历:

function is_iterable($var) {
    return (is_array($var) || $var instanceof Traversable || $var instanceof stdClass);
}
我使用一种简单(也许有点粗俗)的方法来测试“易受攻击性”

当您尝试循环一个不可iterable变量时,PHP会抛出一个警告。通过在尝试迭代之前设置自定义错误处理程序,可以将错误转换为异常,从而使用try/catch块。之后,恢复先前的错误处理程序,以不中断程序流

下面是一个小测试用例(在PHP5.3.15中测试):

PHP 7.1.0,专门为此目的而设计:

该[…]提出了一种新的
iterable
伪类型。此类型类似于
可调用的
,接受多种类型而不是单一类型

iterable
接受任何
数组
或实现
可遍历的对象
。这两种类型都可以使用
foreach
,并且可以在生成器中与
产量
一起使用

此[…]还添加了一个函数
is_iterable()
,该函数返回一个布尔值:
true
,如果某个值是iterable,则该值将被
iterable
伪类型接受,
false
用于其他值


Iterator
IteratorAggregate
不实现
Traversable
。它们是接口,因此没有实现。它们扩展了可遍历的
。除此之外,+1我看不出我做错了什么,但它似乎不适用于对foreach很好的类:
foreach
将适用于不是这些接口实例的类。它只是遍历实例的所有属性。如果您想要自定义行为,您必须实现
Iterator
PHP的伪类型iterable(7.1):-D@NullUserException由于PHP7.1已经实现了
是可写的
函数,您应该在示例代码中添加
,如果函数存在(…)
,则所有对象都可以是每个对象的
,但这样做通常是无意的。并非所有对象都是stdClass的
实例,但正如@Brilliand所指出的,所有对象都可以是每个对象的
。在许多情况下,您会检查是否确实想要
foreach
它,例如
is\u array($var)
返回true或
$var transversable的instanceof
返回true。如果您确实想在任何可以是
foreach
'd的东西上运行
foreach
(只要您知道自己在做什么以及为什么),那么最好用
is_object($var)
替换代码的最后一部分。下一个问题是为什么要使用stdClass?几乎没有任何好处,但也有许多缺点。更新:从PHP7.1开始,本机函数可用。此外,is_iterable(新stdClass)返回false。我认为您应该将您的答案标记为不推荐的somehow我在3v4l.org上运行了一个稍加修改的版本,该版本适用于PHP5.0+:。甚至stdClass也会传递所有的数据。你知道你的方法是否捕捉到了一些东西,而这些东西是不存在的吗?@rambocoder任何一个对象都不会“扩展”stdClass,也不会显式实现Traversable。例如,一些PECL库,例如PHP Imuttable扩展,使用C结构而不是PHP对象。这些对象是可移植的,但上面的函数不能识别它们,因为它们不是基于C级的PHP对象构造。自PHP7以来,有一个新函数。看一看:)@Kamafeather对于未实现Iterable的类或泛型对象(StdCLass)函数失败只是关于通过“数组键”语法直接访问,它与Iterable无关。对于StdCLass它应该为false似乎很奇怪,因为您可以使用与数组相同的foreach对它们进行迭代。我经常将数组和基本对象与迭代对象的函数互换使用,这是主要的sce
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;
}
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
function foo(iterable $iterable) {
    foreach ($iterable as $value) {
        // ...
    }
}
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)