在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 ...
随机推荐
- Java 多线程与并发【原理第一部分笔记】
Java 多线程与并发[原理第一部分笔记] Synchronized synchronized的基本含义以及使用方式 在Java中线程安全问题的主要诱因就是存在共享数据(也称为临界资源)以及存在多条线 ...
- 【笔记】KNN之分类准确度
分类准确度 分类准确度 以sklearn中的手写数字datasets.load_digits为例,其是8*8的图形,具有64个特征值,类别由0到9 我们挑选出666这个图形,将其可视化 X = dig ...
- 【Vulnhub】DC-1靶机
一.信息收集 1.1 环境 kali : 192.168.124.141 DC-1 : 192.168.124.150 1.2 nmap进行扫描 :nmap -sV 192.168.124.150 I ...
- miniFTP项目实战六
项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...
- bootstrap.yaml和application.yaml的区别
bootstrap.yaml 配置一些引导系统启动的参数,这些参数一旦指定后就不会变动了.比如程序的端口号,配置中心的地址等. application.yaml 应用级别的参数配置,可能会根据业务需求 ...
- Linux搭建VNC servere服务
此安装方法只适用于centos7以上的版本 一,安装 以root用户运行以下命令来安装vncserver; yum install tigervnc-server 同样运行以下命令来安装vncvie ...
- Node + Selenium 报错 UnhandledPromiseRejectionWarning: Error: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:5319
安装selenium-webdriver npm i selenium-webdriver 当前安装版本: "selenium-webdriver": "^4.0.0-a ...
- 使用nmap命令扫描开放端口
1.安装nmap 1.下载nmap安装包 下载地址:http://www.nmap.com.cn/ 根据自己需求下载,各种版本都有,我下载的是windows版本,安装版的. 2.安装 基本都是无脑安装 ...
- CNN卷积神经网络详解
前言 在学计算机视觉的这段时间里整理了不少的笔记,想着就把这些笔记再重新整理出来,然后写成Blog和大家一起分享.目前的计划如下(以下网络全部使用Pytorch搭建): 专题一:计算机视觉基础 介 ...
- 物联网协议Coap协议介绍
COAP协议简介 Coap(Constrained Application Protocol)是一种在物联网世界的类web协议,它的详细规范定义在 RFC 7252.COAP名字翻译来就是" ...