在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://www.php.net/manual/zh/class.traversable.php
https://www.php.net/manual/zh/control-structures.foreach.php
https://www.php.net/manual/zh/language.oop5.iterations.php
在PHP中检测一个类是否可以被foreach遍历的更多相关文章
- Java项目中每一个类都可以有一个main方法
Java项目中每一个类都可以有一个main方法,但只有一个main方法会被执行,其他main方法可以对类进行单元测试. public class StaticTest { public static ...
- C++ //多继承语法 C++中允许一个类继承多个类
1 //多继承语法 C++中允许一个类继承多个类 2 #include <iostream> 3 #include <string> 4 using namespace std ...
- Java中的一个类怎么调用另一个类中的方法
如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...
- javascript中检测一个变量的类型
/** * 怎么检测一个变量的类型? * 在js中检测对象类型主要有三种:typeof, instanceof, constructor, 这几种都可以检测对象的类型. * 另外还可以适应jQuery ...
- 2.spring源码-BeanPostProcessor后置处理之ApplicationContextAwareProcessor,实现spring容器中某一个类的bean对象在初始化时需要得到Spring容器内容。
需求:我们的需求是,在spring初始化完毕时,使我们自定义一个类Bird类可以得到spring容器内容. 实现步骤: 1.首先我们来看一下ApplicationContextAwareProcess ...
- Java中增强一个类的几种方法
今天有人问我怎么增强一个类的功能.博客刚好没东西,今天就讲讲增强类. 增强的手段有三种类型: 1.继承或者实现接口:特点是被增强对象不能变,增强的内容不能变. 2.装饰着模式:特点是被增强对象可变,但 ...
- java集合中的一个移除数据陷阱(遍历集合自身并同时删除被遍历数据)
下面是网上的其他解释,更能从本质上解释原因:Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁. Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量 ...
- C#中检测某个类(方法、程序集等各种部分)是否应用了指定的特性以及对特性的一些简单操作
前言:不管是自定义的一些特性,或者是C#中内置的特性,均继承自Attribute这个类,这个类也提供了一些方法,方便我们使用. Attribute类有三个静态方法:1.IsDefined,如果有指定的 ...
- unity3d中检测一个物体是否在摄像机视野范围内
这个脚本最好是把模型对象的锚点设置在最低点.好了直接上脚本.可以直接复制代码,把CS文件拖到一个Camera上,然后把目标拖到targetTran中去就行了. using UnityEngine; u ...
随机推荐
- mybatis generator的generatorConfig.xml配置详解
generatorConfig.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ge ...
- Lab: Brute-forcing a stay-logged-in cookie:点击保持登录状态返回的Cookie里面破解账号密码靶场复盘
靶场内容: 此实验室允许用户在关闭浏览器会话后仍保持登录状态.用于提供此功能的 cookie 容易受到暴力破解. 为了解决实验室问题,暴力破解 Carlos 的 cookie 以访问他的"我 ...
- pikachu CSRF
CSRF简介 CSRF 是 Cross Site Request Forgery 的 简称,中文名为跨域请求伪造在CSRF的攻击场景中,攻击者会伪造一个请求(一般是一个链接)然后欺骗目标用户进行点击, ...
- 程序员作图工具和技巧,你 get 了么?
分享程序员常用的画图软件和小技巧 大家好,我是鱼皮. 说实话,我觉得做个程序员挺好的.日常工作有很多,写代码.对需求.写方案等等,但我最爱画图:流程图.架构图.交互图.功能模块图.UML 类图.部署图 ...
- leetcode 最佳买卖股票时机含冷冻期
这道题算是股票问题的变体之一,主要在于不限制交易次数而存在冷冻期,所以我们需要对我们的dp数组进行改变,第一维是指第几天,第二维是指是否持有股票,在这里因为不限制交易次数k,所以并未涉及第三维度. 同 ...
- Ubuntu18.04忘记root密码,重置root密码
输入命令,更新root密码: sudo passwd root 然后输入新密码,再输入一次确认新密码,新密码更新完毕! 切换root账号: su 如下图所示,发现已经由zyw账号切换到root账号了!
- C# Monitor.TryEnter 源码跟踪
source: Monitor 获取指定对象的独占锁. [MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical, __Dyn ...
- mzy git学习,禁用Fast forward的普通合并(六)
git merge --no-ff -m "msg" x-branch:禁用Fast forward的普通合并 通常,合并分支时,如果可能,Git会用Fast forward模式, ...
- openstack新建实例各种报错解决
最近自己装了下Openstack,零基础安装,参照了网上不少教程. 吃了百家饭的后果,就是出现了一堆不明问题...openstack安装比较复杂,很多配置文件,一个地方配置不正确,可能会导致后面的功能 ...
- 多源最短路径,一文搞懂Floyd算法
前言 在图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径. 在单源正权值最短路径,我们会用Dijkstra ...