在PHP中检测一个类是否可以被foreach遍历

在PHP中,我们可以非常简单的判断一个变量是什么类型,也可以非常方便的确定一个数组的长度从而决定这个数组是否可以遍历。那么类呢?我们要如何知道这个类是否可以通过 foreach 来进行遍历呢?其实,PHP已经为我们提供了一个现成的接口。

class Obj1{

public $v = 'V:Obj1';

private $prv = 'prv:Obj1';

}

$obj1 = new Obj1();

echo $obj1 instanceof Traversable ? 'yes' : 'no', PHP_EOL; // no

class Obj2 implements IteratorAggregate{

public $v = 'V:Obj2';

private $prv = 'prv:Obj2';

public function getIterator(){

return new ArrayIterator([

'v' => $this->v,

'prv' => $this->prv,

]);

}

}

$obj2 = new Obj2();

echo $obj2 instanceof Traversable ? 'yes' : 'no', PHP_EOL; // yes

从上面的例子中可以看出,第一个 \$obj1 无法通过 Traversable 判断,所以它是不能被遍历的。而第二个 $obj2 则是实现了迭代器接口,这个对象是可以通过 Traversable 判断的。在PHP手册中,Traversable 接口正是用于检测一个类是否可以被 foreach 遍历的接口。

这个接口有几个特点:

实现此接口的内建类可以使用 foreach 进行遍历而无需实现 IteratorAggregate 或 Iterator 接口。

这是一个无法在 PHP 脚本中实现的内部引擎接口。IteratorAggregate 或 Iterator 接口可以用来代替它。

也就是说这个接口不需要我们去手工实现,只需要我们的类实现迭代器相关的接口就可以通过这个接口的验证的判断。如果单独去实现这个接口的话,将会报错并提示我们应该去实现 IteratorAggregate 或 Iterator 接口。

// Fatal error: Class ImplTraversable must implement interface Traversable as part of either Iterator or IteratorAggregate in Unknown

class ImplTraversable implements Traversable{

}

其实之前的文章中,我们已经验证过,对象是可以被遍历的,而且并不需要实现什么迭代器接口就可以被 foreach 遍历。它会输出 所有 public 的属性。

// foreach

foreach ($obj1 as $o1) {

echo $o1, PHP_EOL;

}

foreach ($obj2 as $o2) {

echo $o2, PHP_EOL;

}

// V:Obj1

// V:Obj2

// prv:Obj2

也就是说这个 Traversable 接口的作用在实际使用中并不明显。相信我们决大部分人也并没有使用过这个接口来判断过类是否可以被遍历。但是从上面的例子中我们可以看出,迭代器能够自定义我们需要输出的内容。相对来说比直接的对象遍历更加的灵活可控。另外,如果是数组强转对象的情况,Traversable 接口同样无法进行判断。

$arr = [1, 2, 3, 4];

$obj3 = (object) $arr;

echo $obj3 instanceof Traversable ? 'yes' : 'no', PHP_EOL; // no

foreach ($obj3 as $o3) {

echo $o3, PHP_EOL;

}

其实,数组本身就是天然的可迭代对象。这里虽然进行了类型强转,但其实应该将数组强转的对象视为默认实现了迭代的器的对象更合适。当然,这类接口更大的意义还是在于代码规范及强制检查方面。

测试代码:https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/%E5%9C%A8PHP%E4%B8%AD%E6%A3%80%E6%B5%8B%E4%B8%80%E4%B8%AA%E7%B1%BB%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E8%A2%ABforeach%E9%81%8D%E5%8E%86.php

参考文档:

https://www.php.net/manual/zh/class.traversable.phphttps://www.php.net/manual/zh/control-structures.foreach.php

https://www.php.net/manual/zh/language.oop5.iterations.php

php类可以遍历,在PHP中检测一个类是否可以被foreach遍历相关推荐

  1. mave工程中的一个类调用另一个聚合工程的一个类_求求你,别再写上千行的类了好吗...

    专注于Java领域优质技术,欢迎关注 作者:橙味菌 最近在对已有项目进行扩展的时候,发现要改动的一个类它长766行,开放了近40个public接口,我流着泪把它给改完了.为了防止这样的惨剧再次发生在我 ...

  2. java面试题43要使某个类能被同一个包中的其他类访问,但不能被这个包以外的类访问,可以( )

    java面试题43要使某个类能被同一个包中的其他类访问,但不能被这个包以外的类访问,可以( ) A让该类不使用任何关键字 B使用private关键字 C 使用protected关键字 D 使用void ...

  3. python中定义类的关键字_在Python中,定义一个类使用什么关键字?

    [多选题]技术应用的限制包括 [多选题]关于类和对象,下面说法正确的有? [判断题]温度越高,料液的粘度越小,扩散系数越大,可提高膜通量. [单选题]某企业有10台运货车,已知每台车每运行100小时平 ...

  4. 【python】 定义一个Person类,它包含数据成员age, name和gender。从Person中派生一个类Employee,在新类中添加一个数据成员,存储个人的number.等等

    # 定义一个Person类,它包含数据成员age, name和gender. # a. 从Person中派生一个类Employee,在新类中添加一个数据成员,存储个人的number. # 再从Empl ...

  5. 在php中自定义一个类的关键字为( ),精读《未来简史》尔雅章节测验答案

    精读<未来简史>尔雅章节测验答案 更多相关问题 [单选题]当采用环刀法取样时,取样点应位于每层土的()深度处. A. 1/2 B. 1/3 C. 1/4 D. 2/3 [填空题]OSI/R ...

  6. 类的成员变量 猜数字游戏一个类A有一个成员变量v有一个初值100。 * 定义一个类对A类的成员变量v进行猜。 * 如果大了则提示大了小了则提示小了。等于则提示猜测成功。

    /** 类的成员变量 猜数字游戏一个类A有一个成员变量v有一个初值100.* 定义一个类对A类的成员变量v进行猜.* 如果大了则提示大了小了则提示小了.等于则提示猜测成功.*/ import java ...

  7. mave工程中的一个类调用另一个聚合工程的一个类_信息系统管理工程师备考分享(材料重点精炼)——第一章信息化和信息系统(4)...

    本章分享的1.4节的重要考点内容相对来说还是比较多的,里面包括需求.设计.测试等软件工程的内容,同学们学完前几篇文章的分享会发现,第一章与计算机领域的知识的衔接程度还是非常紧密的.我经常会听到很多面授 ...

  8. java中script类_在Scripting java(javax.script)中导入一个类

    我想将我在项目中创建的类导入到我的脚本中 我这样做但它不起作用: function doFunction(){ //Objectif Mensuel importPackage(java.lang); ...

  9. mave工程中的一个类调用另一个聚合工程的一个类_谈谈设计模式:建造者模式在jdk中的体现,它和工厂模式区别?...

    背景 建造模式(Builder模式) 假如有一个需求:盖房子,盖房子过程是一致的:打桩.砌墙.封顶.但是房子是各式各样的,最后盖出来的房子可能是高楼或别墅. 根据直接的思路,不用设计模式思想,我们也许 ...

最新文章

  1. mybatis逆向工程配置文件怎么再偷懒(懒出天际)
  2. 常用的深度学习的linux代码(1.实时监测GPU情况2.当前正常使用的GPU情况3.杀掉特定某个进程4.杀掉特定某个进程)
  3. DHCP企业应用指南
  4. 计算机网络子网划分路由配置实验报告,洛阳理工学院+计算机网络+实验5子网划分路由配置...
  5. 13-一对多左连接查询分步查询(查询所有客户及客户对应的订单)
  6. 吴恩达团队新研究!用MRNet进行膝关节磁共振影像诊断 已媲美医生 | 论文
  7. 线程同步与互斥:POSIX无名信号量
  8. 《中国人工智能学会通讯》——4.40 什么是类人概念学习?
  9. Zookeeper + ActiveMQ 集群整合
  10. c语言幂函数_了解C / C ++中的幂函数
  11. python中match方法中r什么意思_什么是pythonre.match函数?(实例解析)
  12. 思科模拟器之端口聚合技术
  13. bootstrap3 兼容IE8浏览器
  14. C++11 auto关键字的用法
  15. gradle编译错误:Unfortunately you can't have non-Gradle Java modules and Android-Gradle modules in one
  16. 钢结构基本原理试题及答案
  17. miniui展示日历能点击_简单几步,2020年天象导入手机日历
  18. android图片素描效果,将图像转换为android中的铅笔素描
  19. 发字的楷书写法图片_“快”字楷体书法 图片 写法
  20. 捷径社区 - 发现和分享捷径、快捷指令

热门文章

  1. python生成柱状图 不显示_python – Matplotlib图表不显示在PyCharm中
  2. CodeBlocks 汉化教程及多语言
  3. mt.exe : general error c101008d: Failed to write the updated manifest to the resource of file 原因调查
  4. 分式的二阶导数怎么求_为何二阶微分要记为 d²y/dx²?
  5. 苹果6可以分屏吗_苹果减肥法可以吃鸡蛋吗 苹果减肥法做法
  6. html怎么自动设为底部,让底部永远在页面最底部显示的css方法
  7. java 多线程监听同一个端口_使用多线程在Java服务器中同时侦听两个端口
  8. gis影像格式img转为ecw_微图影像地图导出拼接大图的参数说明
  9. 真实序号索引与标签索引的使用
  10. MySQL 怎么变快_如何让mysql索引更快一点