PHP foreach遍历多维数组实现方式


Posted in PHP onNovember 16, 2016

介绍
正常我们的foreach可以按顺序把一维数组里面每个 key => value 打印出来,但是如果是多维数组则需要循环在嵌套循环,或则递归实现,但是这些方式都不够灵活,因为在不确定该数组是几维的情况下,不可能永无止境的嵌套循环,如果采用递归到可以解决,但是如果只想使用foreach全部循环出来该如何实现?

实现方式 一
采用PHP本身自带的迭代器类 RecursiveIteratorIterator

$test_arr = array(1,2,3,array(4,'aa'=>5,6,array(7,'bb'=>8),9,10),11,12); 
  $arrayiter = new RecursiveArrayIterator($test_arr);
  $iteriter = new RecursiveIteratorIterator($arrayiter);
  //直接打印即可按照横向顺序打印出来
  foreach ($iteriter as $key => $val){ 
    echo $key.'=>'.$val; 
  } 
  //结果
  /* 
    0=>1
    1=>2 
    2=>3
    0=>4
    aa=>5
    2=>6
    0=>7
    bb=>8
    4=>9
    5=>10
    4=>11
    5=>12
 */

实现方式 二
自己实现一个类似于 RecursiveIteratorIterator 的迭代器类,实现多维数组横向打印功能

class foreachPrintfArr implements Iterator {
    //当前数组作用域
    private $_items; 
    private $_old_items;
    //保存每次执行数组环境栈
    private $_stack = array(); 

    public function __construct($data=array()){
      $this->_items = $data;
    }

    private function _isset(){
      $val = current($this->_items);

      if (empty($this->_stack) && !$val) {
        return false;
      } else {
        return true;
      }  
    }

    public function current() {
      $this->_old_items = null;
      $val = current($this->_items);

      //如果是数组则保存当前执行环境,然后切换到新的数组执行环境
      if (is_array($val)){
        array_push($this->_stack,$this->_items);
        $this->_items = $val;
        return $this->current();
      }

      //判断当前执行完成后是否需要切回上次执行环境
      //(1) 如果存在跳出继续执行
      //(2) 如果不存在且环境栈为空,则表示当前执行到最后一个元素
      //(3) 如果当前数组环境下一个元素不存在,则保存一下当前执行数组环境 $this->_old_items = $this->_items;
      //然后切换上次执行环境 $this->_items = array_pop($this->_stack) 继续循环, 直到当前数组环境下一个
      //元素不为空为止
      while (1) {
        if (next($this->_items)) {  
          prev($this->_items); break;
        } elseif (empty($this->_stack)) {
          end($this->_items); break;
        } else {
          end($this->_items);
          if (!$this->_old_items) 
            $this->_old_items = $this->_items;
          $this->_items = array_pop($this->_stack);
        }
      }

      return $val;
    }

    public function next() {
      next($this->_items);  
    }

    public function key() {
      // 由于 key() 函数执行在 current() 函数之后
      // 所以在 current() 函数切换执行环境 , 会导致切换之前的执行环境最后一个 key
      // 变成切换之后的key , 所以 $this->_old_items 保存一下切换之前的执行环境
      // 防止key打印出错
      return $this->_old_items ? key($this->_old_items) : key($this->_items);
    }

    public function rewind() {
      reset($this->_items);
    }

    public function valid() {                                       
      return $this->_isset();
    }
  }

内部执行方式

1、foreach 循环我们自定义的foreachPrintfArr类,会自动调用内部这5个方法 valid()、rewind()、key()、next()、current() 我们只需要实现这几个方法即可.

2、调用顺序:
第1次 => rewind -> valid -> current -> key
第2次~n次 =>  next -> valid -> current -> key

$test_arr = array(1,2,3,array(4,'aa'=>5,6,array(7,'bb'=>8),9,10),11,12);
   $iteriter = new foreachPrintfArr($test_arr);
   foreach ($iteriter as $key => $val){
     echo $key.'=>'.$val;
   } 
   //结果:
   /* 
   0=>1
   1=>2
   2=>3
   0=>4
   aa=>5
   2=>6
   0=>7
   bb=>8
   4=>9
   5=>10
   4=>11
   5=>12
   */

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
如何写php程序?
Dec 08 PHP
Discuz!5的PHP代码高亮显示插件(黑暗中的舞者更新)
Jan 29 PHP
服务器变量 $_SERVER 的深入解析
Jul 02 PHP
php中的PHP_EOL换行符详细解析
Oct 26 PHP
PHP中比较时间大小实例
Aug 21 PHP
php使用fgetcsv读取csv文件出现乱码的解决方法
Nov 08 PHP
WordPress迁移时一些常见问题的解决方法整理
Nov 24 PHP
PHP记录和读取JSON格式日志文件
Jul 07 PHP
php实现数据库的增删改查
Feb 26 PHP
PHP设计模式之装饰器模式实例详解
Feb 07 PHP
PHP dirname(__FILE__)原理及用法解析
Oct 28 PHP
PHP快速导出百万级数据到CSV或者EXCEL文件
Nov 27 PHP
php数据库操作model类(使用__call方法)
Nov 16 #PHP
php实现的简单数据库操作Model类
Nov 16 #PHP
iOS自定义提示弹出框实现类似UIAlertView的效果
Nov 16 #PHP
PHP中串行化用法示例
Nov 16 #PHP
PHP单态模式简单用法示例
Nov 16 #PHP
php实现替换手机号中间数字为*号及隐藏IP最后几位的方法
Nov 16 #PHP
php实现当前页面点击下载文件的实例代码
Nov 16 #PHP
You might like
Email+URL的判断和自动转换函数
2006/10/09 PHP
PHP上传文件时自动分配路径的方法
2015/01/09 PHP
php+ajax实现无刷新的新闻留言系统
2020/12/21 PHP
Thinkphp 框架基础之源码获取、环境要求与目录结构分析
2020/04/27 PHP
利用ajaxfileupload插件实现文件上传无刷新的具体方法
2013/06/08 Javascript
node.js使用npm 安装插件时提示install Error: ENOENT报错的解决方法
2014/11/20 Javascript
详解BootStrap中Affix控件的使用及保持布局的美观的方法
2016/07/08 Javascript
微信小程序 HTTPS报错整理常见问题及解决方案
2016/12/14 Javascript
详解webpack+gulp实现自动构建部署
2017/06/29 Javascript
bootstrap模态框嵌套、tabindex属性、去除阴影的示例代码
2017/10/17 Javascript
React Native使用百度Echarts显示图表的示例代码
2017/11/07 Javascript
解决element UI 自定义传参的问题
2018/08/22 Javascript
从0到1构建vueSSR项目之node以及vue-cli3的配置
2019/03/07 Javascript
elementUI 动态生成几行几列的方法示例
2019/07/11 Javascript
vue v-for直接循环数字实例
2019/11/07 Javascript
对Python中plt的画图函数详解
2018/11/07 Python
Python values()与itervalues()的用法详解
2019/11/27 Python
Python的pygame安装教程详解
2020/02/10 Python
解决 jupyter notebook 回车换两行问题
2020/04/15 Python
Python unittest如何生成HTMLTestRunner模块
2020/09/08 Python
python3实现飞机大战
2020/11/29 Python
CSS3 伪类选择器 nth-child()说明
2010/07/10 HTML / CSS
CSS3实现10种Loading效果
2016/07/11 HTML / CSS
39美元购买一副眼镜或太阳镜:39DollarGlasses.com
2018/06/17 全球购物
三陽商会官方网站:Sanyo iStore
2019/05/15 全球购物
.NET是怎么支持多种语言的
2015/02/24 面试题
linux面试题参考答案(11)
2016/11/26 面试题
介绍一下gcc特性
2015/10/31 面试题
党员公开承诺书
2014/03/25 职场文书
软件项目实施计划书
2014/05/02 职场文书
2014年护理部工作总结
2014/11/14 职场文书
2015年度村委会工作总结
2015/04/29 职场文书
创业计划书之个人工作室
2019/08/22 职场文书
Mysql案例刨析事务隔离级别
2021/09/25 MySQL
css3应用示例:新增的选择器
2022/03/16 HTML / CSS
SpringBoot Http远程调用的方法
2022/08/14 Java/Android