对于php来说,foreach是非常方便好用的一个语法,几乎对于每一个PHPer它都是日常接触最多的请求之一。那么对象是否能通过foreach来遍历呢?

答案是肯定的,但是有个条件,那就是对象的遍历只能获得它的公共属性。

// 普通遍历
class A
{
public $a1 = '1';
public $a2 = '2';
public $a3 = '3'; private $a4 = '4';
protected $a5 = '5'; public $a6 = '6'; public function test()
{
echo 'test';
}
}
$a = new A();
foreach ($a as $k => $v) {
echo $k, '===', $v, PHP_EOL;
} // a1===1
// a2===2
// a3===3
// a6===6

不管是方法还是受保护或者私有的变量,都无法遍历出来。只有公共的属性才能被遍历出来。其实,我们之前在讲设计模式时讲过的迭代器模式就是专门用来进行对象遍历的,而且PHP已经为我们准备好了相关的接口,我们只需要去实现这个接口就可以完成迭代器模式的创建了。具体的内容可以参考之前的设计模式系列文章:PHP设计模式之迭代器模式

// 实现迭代器接口
class B implements Iterator
{
private $var = []; public function __construct($array)
{
if (is_array($array)) {
$this->var = $array;
}
} public function rewind()
{
echo "rewinding\n";
reset($this->var);
} public function current()
{
$var = current($this->var);
echo "current: $var\n";
return $var;
} public function key()
{
$var = key($this->var);
echo "key: $var\n";
return $var;
} public function next()
{
$var = next($this->var);
echo "next: $var\n";
return $var;
} public function valid()
{
$var = $this->current() !== false;
echo "valid: {$var}\n";
return $var;
}
} $b = new B([1, 2, 3, 4]); foreach ($b as $k => $v) {
echo $k, '===', $v, PHP_EOL;
} // rewinding
// current: 1
// valid: 1
// current: 1
// key: 0
// 0===1
// next: 2
// current: 2
// valid: 1
// current: 2
// key: 1
// 1===2
// next: 3
// current: 3
// valid: 1
// current: 3
// key: 2
// 2===3
// next: 4
// current: 4
// valid: 1
// current: 4
// key: 3
// 3===4
// next:
// current:
// valid:

假如今天的文章只是讲之前讲过的迭代器模式,那就太没意思了,所以,咱们还要来学习一个更有意思的应用。那就是让对象可以像数组一样进行操作。这个其实也是使用PHP早已为我们准备好的一个接口:ArrayAccess。

// 让类可以像数组一样操作
class C implements ArrayAccess, IteratorAggregate
{
private $container = [];
public function __construct()
{
$this->container = [
"one" => 1,
"two" => 2,
"three" => 3,
];
}
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
public function offsetGet($offset)
{
return isset($this->container[$offset]) ? $this->container[$offset] : null;
} public function getIterator() {
return new B($this->container);
}
} $c = new C();
var_dump($c); $c['four'] = 4;
var_dump($c); $c[] = 5;
$c[] = 6;
var_dump($c); foreach($c as $k=>$v){
echo $k, '===', $v, PHP_EOL;
} // rewinding
// current: 1
// valid: 1
// current: 1
// key: one
// one===1
// next: 2
// current: 2
// valid: 1
// current: 2
// key: two
// two===2
// next: 3
// current: 3
// valid: 1
// current: 3
// key: three
// three===3
// next: 4
// current: 4
// valid: 1
// current: 4
// key: four
// four===4
// next: 5
// current: 5
// valid: 1
// current: 5
// key: 0
// 0===5
// next: 6
// current: 6
// valid: 1
// current: 6
// key: 1
// 1===6
// next:
// current:
// valid:

这个接口需要我们实现四个方法:

  • offsetSet($offset, $value),根据偏移量设置值
  • offsetExists($offset),根据偏移量确定是否存在内容
  • offsetUnset($offset),根据偏移量删除内容
  • offsetGet($offset),根据依稀量获取内容

这里的偏移量就是我们常说的下标。通过实现这四个方法,我们就可以像操作数组一样的操作对象。当然,日常开发中我们可能并不会很经常的使用包括迭代器在内的这些对象遍历的能力。通常我们会直接去将对象转换成数组 (array) obj 来进行下一步的操作。不过,在java中,特别是JavaBean中会经常在类的内部有一个 List 为自己的对象来表示自身的集合状态。通过对比,我们发现PHP也完全可以实现这样的能力,而且使用迭代器和 ArrayAccess 接口还能够更方便的实现类似的能力。这是非常有用的一种知识扩展,或许下一个项目中你就能运用上这些能力哦!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/201912/source/PHP%E6%80%8E%E4%B9%88%E9%81%8D%E5%8E%86%E5%AF%B9%E8%B1%A1%EF%BC%9F.php

参考文档:

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

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

PHP怎么遍历对象?的更多相关文章

  1. 111. for(元素变量x:遍历对象obj)

    package com.chongrui.test;/* * for(元素变量x:遍历对象obj){ * 引用X的java语句 *  * } *  *  * */public class test { ...

  2. jquery遍历对象,数组,集合

    1.jquery 遍历对象 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTM ...

  3. jquery中each遍历对象和数组示例

    通用遍历方法,可用于遍历对象和数组.$().each(),回调函数拥有两个参数: 第一个为对象的成员或数组的索引,第二个为对应变量或内容.如需退出each循环可使回调函数返回false 现有如下两个s ...

  4. jQuery遍历对象、数组、集合实例

    1.jquery 遍历对象 复制代码代码如下:   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ...

  5. JS遍历对象或者数组

    一.纯js实现 <script> var obj = {"player_id":"GS001","event_id":" ...

  6. JS完成页面跳转并传参的方法|附加:循环遍历对象

    此方法只能传递较少参数 方法如下: <a href='page/index.html'>跳转</a> 以上是正常写法,如果要传参按一下写法: <!--参数写在?后面,多个 ...

  7. javascript . 05 json的组成、for...in 遍历对象、简单数据类型与复杂数据类型的传值与传址、内置对象

    对象字面量  JSON var obj = { aaa :999}; var json={"aaa":999,"bbb":888}; "kay&quo ...

  8. JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序

    前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...

  9. es6五种遍历对象属性的方法 - 表格整理

    ES6 一共有5种方法可以遍历对象的属性. (1)for...in for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性). (2)Object.keys(obj) Obje ...

  10. for/in 循环遍历对象的属性

    for/in 语句循环遍历对象的属性. js中获取key得到某对象中相对应的value的方法:obj.key js中根据动态key得到某对象中相对应的value的方法有二: 一.var key = & ...

随机推荐

  1. MongoDB-01-基础

    mongodb逻辑结构 Mongodb 逻辑结构 MySQL逻辑结构 库 (database) 库 集合(collection) 表 文档(document) 数据行 安装部署 1 系统准备 1 这里 ...

  2. 常见web中间件漏洞(五)weblogic漏洞

    继续整理有关中间件漏洞思路(仅做简单思路整理,不是复现,复现请参考大佬们的长篇好文,会在文章中列举部分操作) WebLogic是Oracle公司出品的一个application server,确切的说 ...

  3. STP工作流程

    第一步:选择一个根网桥: 第二步:在每个非根网乔上选举一个根端口: 第三步:在每个网段上选举一个指定端口: 第四步:阻塞非根,非指定端口:

  4. Android WorkManager工作约束,延迟与查询工作

    WorkManager工作约束,延迟与查询工作 本文可能会混用"工作"与"任务"这两个词. 本文例子使用Kotlin 准备一个工作类(任务)UploadWork ...

  5. Are You OK?主键、聚集索引、辅助索引

    每张表都一定存在主键吗? 关于这个问题,各位小伙伴们不妨先自己想一想,再往下寻找答案. 首先公布结论:对于 InnoDB 存储引擎来说,每张表都一定有个主键(Primary Key)! 让人非常遗憾的 ...

  6. CentOS8 安装MySQL5.7

    CentOS_8 安装MySQL5.7 1.在安装之前,如果你的系统曾经安装过Mariadb,请先卸载:yum remove mariadb*2.安装依赖 yum install -y epel-re ...

  7. metasploit的数据库配置

    metasploit所处位置:/usr/share/metasploit-framework msf数据库连接命令:db_connect msf:msfadmin@127.0.0.1/msf 1.启动 ...

  8. pip的问题 Can't connect to HTTPS URL because the SSL module is not available

    pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail ...

  9. C++智能指针的原理和实现

    一.智能指针起因 在C++中,动态内存的管理是由程序员自己申请和释放的,用一对运算符完成:new和delete. new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针: delete:指向 ...

  10. linux(5)----------防火墙的配置

    1.安装:    yum install firewalld 2.启动:    service firewalld start 3.检查状态:        service firewalld sta ...