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)